@charset "UTF-8";

/* ==========================================================================
   CIBHER — hero field

   Replaces a 643 KB raster of Matrix-style green digital rain. That image was
   a direct violation of PRODUCT.md's first anti-reference ("no neon-on-black,
   Matrix-style terminals, cyberpunk gradients, or techno-glitch visual
   clichés") and it was the LCP element on every marketing page.

   What this is instead: two line lattices at slightly different periods and
   angles, drifting against each other. Where they coincide they produce moiré
   interference — alignment appearing and dissolving.

   Why this and not a particle mesh: the mesh is the reflex answer one tier
   below the Matrix, and it means nothing. This means two things at once. The
   product's whole act is checking one artifact against another for a match
   before a document leaves the machine; and ML-KEM-768, the primitive the
   product is built on, is lattice cryptography. The picture is the mechanism.

   Zero image bytes. No layout properties are animated — the drift is transform
   on two pseudo-elements, so it stays on the compositor.
   ========================================================================== */

.cib-hero-field {
  position: absolute;
  inset: 0;
  overflow: hidden;
  z-index: var(--z-base, 0);
  pointer-events: none;

  /* Committed single-hue ground. The tonal scale is the brand; depth comes
     from layering, so the ground is three pools rather than one flat fill. */
  background-color: var(--c-bg, #03120c);
  background-image:
    radial-gradient(58% 46% at 76% 8%, oklch(0.32 0.07 162 / .50), transparent 68%),
    radial-gradient(46% 44% at 12% 88%, oklch(0.38 0.08 162 / .30), transparent 70%),
    radial-gradient(150% 110% at 40% 62%, oklch(0.13 0.035 160 / .96), transparent 58%);
}

/* The two lattices. Same construction, different period and rotation, which is
   what produces the interference. Each is oversized and centred so rotation
   never exposes an edge. */
.cib-hero-field::before,
.cib-hero-field::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 190%;
  height: 190%;
  transform-origin: 50% 50%;
  will-change: transform;

  /* Energy is pulled away from the centre so headline text sits on calm
     ground. The mask is what keeps this a background and not a pattern. */
  -webkit-mask-image: radial-gradient(78% 78% at 26% 74%, transparent 12%, #000 82%);
  mask-image: radial-gradient(78% 78% at 26% 74%, transparent 12%, #000 82%);
}

.cib-hero-field::before {
  background-image:
    repeating-linear-gradient(
      0deg,
      oklch(0.72 0.14 163 / .16) 0 1px,
      transparent 1px 38px
    ),
    repeating-linear-gradient(
      90deg,
      oklch(0.72 0.14 163 / .16) 0 1px,
      transparent 1px 38px
    );
  animation: cib-lattice-a 96s linear infinite;
}

.cib-hero-field::after {
  background-image:
    repeating-linear-gradient(
      0deg,
      oklch(0.82 0.16 163 / .12) 0 1px,
      transparent 1px 45px
    ),
    repeating-linear-gradient(
      90deg,
      oklch(0.82 0.16 163 / .12) 0 1px,
      transparent 1px 45px
    );
  animation: cib-lattice-b 132s linear infinite;
}

/* Linear, deliberately. The shared motion law asks for exponential ease-out,
   which is correct for a discrete transition with a beginning and an end. This
   is a continuous ambient loop: any easing would read as a stutter every cycle. */
@keyframes cib-lattice-a {
  from { transform: translate(-50%, -50%) rotate(0deg)   scale(1); }
  50%  { transform: translate(-50%, -50%) rotate(0.9deg) scale(1.05); }
  to   { transform: translate(-50%, -50%) rotate(0deg)   scale(1); }
}

@keyframes cib-lattice-b {
  from { transform: translate(-50%, -50%) rotate(-1.4deg) scale(1.04); }
  50%  { transform: translate(-50%, -50%) rotate(0.5deg)  scale(1); }
  to   { transform: translate(-50%, -50%) rotate(-1.4deg) scale(1.04); }
}

/* A single slow bloom, low and off-centre: the moment of alignment, not a
   glow effect for its own sake. */
.cib-hero-field > .cib-hero-bloom {
  position: absolute;
  left: 78%;
  bottom: 14%;
  width: min(95vw, 1150px);
  aspect-ratio: 1;
  transform: translateX(-50%);
  background: radial-gradient(
    circle at 50% 50%,
    oklch(0.70 0.14 163 / .26),
    oklch(0.66 0.13 163 / .09) 40%,
    transparent 66%
  );
  animation: cib-bloom 22s ease-in-out infinite;
}

@keyframes cib-bloom {
  0%, 100% { opacity: .55; }
  50%      { opacity: 1; }
}

/* Grain. Without it the gradients band visibly on wide dark displays, and
   banding is the tell that separates a designed surface from a CSS default. */
.cib-hero-field > .cib-hero-grain {
  position: absolute;
  inset: -50%;
  opacity: .16;
  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='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* A hairline where the field meets the page below: a ruled edge, in keeping
   with an instrument rather than a fade-to-nothing. */
.cib-hero-field::marker { content: ""; }

@media (prefers-reduced-motion: reduce) {
  .cib-hero-field::before,
  .cib-hero-field::after,
  .cib-hero-field > .cib-hero-bloom {
    animation: none;
  }
  /* Frozen at an offset that still shows interference, so the still frame is
     composed rather than merely stopped. */
  .cib-hero-field::after {
    transform: translate(-50%, -50%) rotate(-1.1deg) scale(1.03);
  }
}

/* --------------------------------------------------------------------------
   Quiet variant — secondary bands.

   Same field, pulled back: the interference should register as texture behind
   body copy, not compete with it. Used where a stock 3D-render banner used to
   sit. No bloom; that belongs to the hero alone.
   -------------------------------------------------------------------------- */
.cib-hero-field--quiet {
  background-image:
    radial-gradient(80% 60% at 78% 18%, oklch(0.29 0.06 162 / .34), transparent 72%),
    radial-gradient(90% 70% at 10% 90%, oklch(0.13 0.03 160 / .85), transparent 68%);
}

.cib-hero-field--quiet::before { opacity: .5; animation-duration: 150s; }
.cib-hero-field--quiet::after  { opacity: .38; animation-duration: 190s; }

/* --------------------------------------------------------------------------
   Section hosts. The generated Mobirise CSS is rewritten wholesale on every
   re-export, so the rules that neutralise its raster backgrounds live here.
   -------------------------------------------------------------------------- */
.header18.cid-v9M6OLYlJl {
  background-image: none !important;
  background-color: var(--c-bg, #03120c) !important;
  position: relative;
}

/* The 50%-black scrim existed to make white text legible over a photograph.
   The field is already a composed dark ground, so the scrim would only mute it. */
.header18.cid-v9M6OLYlJl .mbr-overlay { display: none !important; }

.article13.cid-v9M6OLY38r { position: relative; }
.article13.cid-v9M6OLY38r .mbr-fallback-image { background-image: none !important; }
