/* ══════════════════════════════════════════════════════════════════════
   SITEWIDE AMBIENT FIELD
   Added 2026-08-08. Loaded by index.html, about.html and every page under
   solutions/, and it is the single source of truth for what "the
   background" means on this site. Nothing here may be redeclared inline
   in a page: the whole point is that no section can drift.

   THE MECHANISM
   One position:fixed element, written once directly after <body>, at
   z-index -10. It does not scroll. The sections travel across it, so the
   page is one continuous surface instead of eight boxes each running its
   own local weather. Taken from nogalsolutions.tech, verified against
   their shipped HTML rather than guessed from a screenshot.

   Two deliberate departures from theirs: their blooms are static, ours
   drift on long clocks so the field breathes; and the colours are
   brand.md's emerald and blue, never their crimson.

   WHY THERE IS NO filter:blur() IN HERE
   A wide radial-gradient is already soft and composites for free. A
   blurred layer at viewport size repaints on every scroll frame, and is
   the usual reason a "premium background" destroys mobile framerate.

   WHY <body> CARRIES NO BACKGROUND
   Load-bearing, not tidying. <html> forms the root stacking context, and
   paint order inside it is (1) html's own background, (2) negative
   z-index descendants, (3) the backgrounds of in-flow block descendants.
   body is (3). A body that keeps bg-paper therefore paints straight over
   a z-index:-10 field and the entire effect silently does nothing. The
   bg-paper / dark:bg-night utilities were removed from every <body> tag
   for the same reason: a class beats an element selector on specificity.
   ══════════════════════════════════════════════════════════════════════ */

html { background-color: #F2FAF6; }
html.dark { background-color: #060F1F; }

.bg-field { position: fixed; inset: 0; z-index: -10; pointer-events: none; overflow: hidden; }
.bg-field .bloom { position: absolute; will-change: transform; }
.bg-field .lt { position: absolute; inset: 0; }
.dark .bg-field .lt { display: none; }
.bg-field .dk { position: absolute; inset: 0; display: none; }
.dark .bg-field .dk { display: block; }

@keyframes field-drift-a {
  0%,100% { transform: translate3d(0,0,0) scale(1); }
  50%     { transform: translate3d(-3%, 3.5%, 0) scale(1.10); }
}
@keyframes field-drift-b {
  0%,100% { transform: translate3d(0,0,0) scale(1.05); }
  50%     { transform: translate3d(4%, -2.5%, 0) scale(.95); }
}
.bloom-a { animation: field-drift-a 34s ease-in-out infinite; }
.bloom-b { animation: field-drift-b 42s ease-in-out infinite; }
.bloom-c { animation: field-drift-a 52s ease-in-out infinite; }

/* Dark only. Stops four blooms reading as four separate lamps and pulls
   the eye back toward the middle column. */
.bg-vignette { position: absolute; inset: 0;
  background: radial-gradient(ellipse 70% 60% at 50% 45%, transparent 35%, rgba(0,0,0,.42) 100%); }

/* Grain, hoisted to the page level. Same pre-rasterised tile the old
   per-section .grain used, declared once here instead of once per
   section, so scrolling never re-runs the SVG filter. */
.bg-grain { position: absolute; inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity: .13; mix-blend-mode: multiply; }
.dark .bg-grain { opacity: .09; mix-blend-mode: overlay; }

/* ---- Masked textures ----------------------------------------------
   Every grid texture on the site now carries a mask so it fades out
   instead of stopping at a hard edge. Nogal does this on his hero grid
   and it is most of why his page has no seams: an unmasked texture cuts
   a visible rectangle into the ambient field underneath it.
   Per brand.md, "subtle dotted grids". ---- */
.dot-grid { background-image: radial-gradient(rgba(8,33,38,.10) 1px, transparent 1px); background-size: 26px 26px;
  -webkit-mask-image: radial-gradient(ellipse 82% 64% at 50% 0%, #000 12%, transparent 72%);
          mask-image: radial-gradient(ellipse 82% 64% at 50% 0%, #000 12%, transparent 72%); }
.dark .dot-grid { background-image: radial-gradient(rgba(242,250,246,.09) 1px, transparent 1px); }
/* Was dark-only, because the one block that used it was dark in both
   themes. Now themed like everything else in #solutions. */
.dot-grid-invert { background-image: radial-gradient(rgba(8,33,38,.085) 1px, transparent 1px); background-size: 26px 26px;
  -webkit-mask-image: radial-gradient(ellipse 86% 70% at 50% 4%, #000 14%, transparent 74%);
          mask-image: radial-gradient(ellipse 86% 70% at 50% 4%, #000 14%, transparent 74%); }
.dark .dot-grid-invert { background-image: radial-gradient(rgba(242,250,246,.075) 1px, transparent 1px); }

/* ---- The recessed block, faded in and out ----
   Used by #solutions on the homepage. The fill lives on a
   pseudo-element rather than on the section itself, so the mask can
   taper it without also tapering the content sitting on top. An opaque
   section paints a hard rectangle over the field and the transition
   arrives as a guillotine edge; this way the page eases into the block
   over 140px and lifts back out of it over 140px.

   CHANGED 2026-08-10. This used to paint #060F1F in BOTH themes: the
   section was a deliberate dark block that stayed dark on a light page,
   and the modal, cards and Tech Wall inside it were hardcoded to match.
   Irvin's call is that light mode should be light here like everywhere
   else ("it is already good in dark"), so the light fill is now a faint
   ink wash that recesses the block a step below the page rather than
   inverting it. Dark mode is unchanged, down to the hex.

   The mask still earns its place in light mode: the wash has an edge like
   any other fill, and tapering it is what keeps the block from reading as
   a pasted rectangle over the ambient field.

   isolation:isolate scopes the -1 to this section. Without it the
   pseudo-element escapes to the root stacking context and lands in the
   same negative band as .bg-field, where the two fight over paint order. */
.dark-block { isolation: isolate; }
.dark-block::before {
  content: ''; position: absolute; inset: 0; z-index: -1; background: rgba(8,33,38,.045);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 140px, #000 calc(100% - 140px), transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 140px, #000 calc(100% - 140px), transparent 100%);
}
/* In dark mode the page is already night, so the block has to go a step
   deeper than the page or the theme switch reads as nothing at all. */
.dark .dark-block::before { background: #030A16; }

@media (prefers-reduced-motion: reduce) {
  .bg-field .bloom { animation: none !important; }
}
