/* ===========================================================================
   Hex lattice — the brand motif as a system instead of 32 pictures
   ===========================================================================

   What this replaces
   ------------------

   The live site draws its hexagon decoration with raster files: left-cells,
   right-cells, cases-cells, cases-left-cells, client-cells, client-right-cells,
   left-grey-cells, hero-cells, footer-cell, medium-left-cell, small-left-cell,
   orange-cell, Union.png and more -- 32 files, ~130 KB, pulled in by 44 separate
   CSS rules, all of them variations on the same two outlined hexagons.

   Every one of those variations exists because the motif was a *picture*:

     * a different colour needed a different file (grey-cells, orange-cell);
     * a different size needed a different file (small-, medium-);
     * the other side of the page needed a different file (left-, right-),
       which is also why none of it mirrors under RTL;
     * a different section needed a different crop (cases-, client-, footer-).

   Here it is one shape, drawn as vector geometry, with colour, scale, fade and
   side all controlled from CSS. One token replaces the set, every variant
   becomes a property rather than a download, and it is crisp on any display
   because there is no pixel grid to run out of.

   How it works
   ------------

   `--hex-lattice` is a tileable honeycomb drawn in SVG as plain black strokes,
   and it is used as a **mask**, never as a background image. That is the whole
   trick: a mask takes its colour from whatever is painted underneath, so the
   same single asset can be a pale cyan line on the light ground, a bright one on
   the dark ground, or a gradient -- without a second file, and without the
   washed-out look you get from fading a pre-coloured PNG with `opacity`.

   The tile is a true honeycomb unit: pointy-top hexagons of radius 100 in a
   173.205 x 300 viewBox, which is a width-to-height ratio of exactly sqrt(3).
   `--hex-tile` keeps that ratio, so changing `--hex-w` rescales the lattice
   without distorting it. The geometry is symmetric about its vertical axis, so
   it mirrors for free under RTL -- the reason `left-cells` and `right-cells`
   collapse into one thing here.

   Usage
   -----

       <section class="has-hex">
         <div class="hex-field hex-field--end" aria-hidden="true"></div>
         ...content...
       </section>

   `.has-hex` establishes the positioning context and lifts the content above
   the decoration. The field is `aria-hidden` and `pointer-events:none`: it is
   ornament, and nothing about it should reach the accessibility tree or
   intercept a click.

   Add `<i class="hex-glow"></i>` inside the field and call `initHexGlow()` for
   the pointer spotlight.
   =========================================================================== */

:root {
  /* One hexagon's width. Everything else derives from it. */
  --hex-w: 104px;

  /* The lattice itself: five hexagons whose union tiles the plane. Stroke width
     2 against a 173.205-wide viewBox renders near 1.2px at the default
     --hex-w, and scales with it -- larger hexagons get proportionally heavier
     lines, which is what keeps the weight looking right rather than spidery. */
  --hex-lattice: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 173.205 300'%3E%3Cg fill='none' stroke='%23000' stroke-width='2' stroke-linejoin='round'%3E%3Cpath d='M0 -100 86.603 -50 86.603 50 0 100 -86.603 50 -86.603 -50Z'/%3E%3Cpath d='M173.205 -100 259.808 -50 259.808 50 173.205 100 86.603 50 86.603 -50Z'/%3E%3Cpath d='M86.603 50 173.205 100 173.205 200 86.603 250 0 200 0 100Z'/%3E%3Cpath d='M0 200 86.603 250 86.603 350 0 400 -86.603 350 -86.603 250Z'/%3E%3Cpath d='M173.205 200 259.808 250 259.808 350 173.205 400 86.603 350 86.603 250Z'/%3E%3C/g%3E%3C/svg%3E");

  /* What the lattice is made of. A gradient rather than a flat colour, because
     a flat stroke across a large field reads as wallpaper -- the shift along
     its length is what makes it look lit rather than printed. */
  --hex-paint: linear-gradient(145deg,
                 color-mix(in oklab, var(--hex-accent, #00AAD3) 85%, white),
                 var(--hex-accent, #00AAD3) 55%,
                 color-mix(in oklab, var(--hex-accent, #00AAD3) 35%, transparent));

  /* The second mask layer. The lattice alone covers everything edge to edge;
     this is what turns it from a tiled pattern into an ambient field that
     belongs to one corner and dissolves before it reaches the text. */
  --hex-fade: radial-gradient(120% 90% at 100% 0%, #000 0%, transparent 68%);

  --hex-opacity: .5;
}

/* Positioning context for a section that carries a field. The field is painted
   underneath; everything else in the section is lifted above it. */
.has-hex {
  position: relative;
  isolation: isolate;
}

.has-hex > *:not(.hex-field) {
  position: relative;
  z-index: 1;
}

.hex-field {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  opacity: var(--hex-opacity);
  background: var(--hex-paint);

  /* Two mask layers intersected: the honeycomb, and the fade that decides how
     much of it survives. `intersect` is the standard keyword; the -webkit-
     pair below it is the older Safari spelling of the same operation. */
  -webkit-mask-image: var(--hex-lattice), var(--hex-fade);
  -webkit-mask-size: var(--hex-w) calc(var(--hex-w) * 1.7320508), 100% 100%;
  -webkit-mask-repeat: repeat, no-repeat;
  -webkit-mask-composite: source-in;
  mask-image: var(--hex-lattice), var(--hex-fade);
  /* The sqrt(3) ratio is the tile's own geometry -- it comes from the 173.205 x
     300 viewBox, and changing one without the other stops the honeycomb tiling
     seamlessly.

     Written out here rather than precomposed as a `--hex-tile` token in :root,
     which is what this did first and which silently broke every density
     modifier. A custom property's `var()`s are substituted against the element
     the property is *declared* on, so a `--hex-tile` defined in :root locks in
     the root's `--hex-w` and inherits that one resolved value everywhere --
     setting `--hex-w` on a field would change nothing. Resolving it at the point
     of use is what makes the modifiers below work at all. */
  mask-size: var(--hex-w) calc(var(--hex-w) * 1.7320508), 100% 100%;
  mask-repeat: repeat, no-repeat;
  mask-composite: intersect;
}

/* --- Where the field comes from ------------------------------------------ */
/* Written with logical positions, so a field anchored to the inline end sits on
   the right in English and the left in Arabic without a second rule. The old
   assets could not do this: `right-cells.webp` is a different file from
   `left-cells.webp`, so an RTL page showed the decoration on the wrong side. */

.hex-field--end   { --hex-fade: radial-gradient(120% 90% at 100% 0%, #000 0%, transparent 68%); }
.hex-field--start { --hex-fade: radial-gradient(120% 90% at 0% 0%, #000 0%, transparent 68%); }
.hex-field--bottom{ --hex-fade: radial-gradient(110% 80% at 50% 100%, #000 0%, transparent 70%); }
.hex-field--band  { --hex-fade: linear-gradient(180deg, transparent, #000 45%, transparent); }
.hex-field--full  { --hex-fade: radial-gradient(90% 90% at 50% 45%, #000 0%, transparent 75%); }

:where(html[dir="rtl"]) .hex-field--end   { --hex-fade: radial-gradient(120% 90% at 0% 0%, #000 0%, transparent 68%); }
:where(html[dir="rtl"]) .hex-field--start { --hex-fade: radial-gradient(120% 90% at 100% 0%, #000 0%, transparent 68%); }

/* --- Density -------------------------------------------------------------- */
/* The whole reason the old set had small-, medium- and full-size files. */

.hex-field--fine  { --hex-w: 58px;  }
.hex-field--wide  { --hex-w: 168px; }
.hex-field--vast  { --hex-w: 280px; }

/* --- The pointer spotlight ------------------------------------------------ */
/*
   A circle of light that exists only where the lattice does, because it is a
   child of the masked element and inherits its mask. The brand mark lights up
   under the cursor instead of sitting there.

   It moves by `transform`, never by `left`/`top` or background-position, so it
   is composited rather than repainted -- the difference between this being free
   and it costing a paint on every mouse move.
*/
.hex-glow {
  position: absolute;
  /* Anchored at the host's centre and offset from there, rather than positioned
     from the corner. A transform percentage resolves against the *element's own*
     box, so a corner anchor has no way to express "centre of the section" as a
     fallback -- it would sit at 0,0 until the first pointer event, which is
     exactly where it must not be. */
  inset-inline-start: 50%;
  top: 50%;
  width: var(--hex-glow-size, clamp(13rem, 38vw, 32rem));
  aspect-ratio: 1;
  display: block;
  /* Near-white at the core: the lattice is already accent-coloured, so lighting
     it with more of the same accent reads as nothing. Going up to white is what
     makes the line look lit rather than merely thicker. */
  background: radial-gradient(circle closest-side,
                #fff 0%,
                color-mix(in oklab, var(--hex-accent, #00AAD3) 85%, white) 38%,
                transparent 72%);
  transform: translate3d(calc(-50% + var(--hex-dx, 0px)), calc(-50% + var(--hex-dy, 0px)), 0);
  opacity: 0;
  /* The transform transition makes the light trail the pointer by a beat rather
     than being welded to it, which is what stops it reading as a cursor. */
  transition: opacity .45s ease, transform .4s cubic-bezier(.16, 1, .3, 1);
  will-change: transform;
}

.has-hex:hover .hex-glow { opacity: 1; }

/* --- Motion and fallbacks ------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .hex-glow { display: none; }
}

/*
  If masking is unavailable the field would paint as a solid gradient block over
  the section, which is far worse than no decoration at all. Fail to nothing.
  Every browser this project targets supports masks; this is the floor, not a
  supported path.
*/
@supports not ((mask-composite: intersect) or (-webkit-mask-composite: source-in)) {
  .hex-field { display: none; }
}

/* ===========================================================================
   Circuit layer — the glowing-PCB look, in the place it belongs
   ===========================================================================

   The reference for this is the stock "AI circuit board" artwork: glowing blue
   traces, pads, a chip at the centre. That look does not survive being a logo --
   it is built from glows, gradients and hairlines, none of which exist at 16px,
   in one ink, or on an embroidered shirt. But it is exactly right as an ambient
   field, and the honeycomb is already a trace network: hexagon edges meet at
   120 degrees, which is how a PCB routes when it is not routing at 45.

   So this adds two things to the lattice rather than replacing it:

     --hex-circuit  the same tile with a pad at every vertex, which is the one
                    detail that makes a line network read as a board;
     .hex-pulse     a bar of light that sweeps across, inherits the field's mask
                    and therefore lights only the traces.

   The sweep is a transform on a single element, so it composites. Animating the
   mask position or a background-position instead would repaint a full-width
   layer on every frame, which is where effects like this usually go wrong.
   =========================================================================== */

:root {
  --hex-circuit: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 173.205 300'%3E%3Cg fill='none' stroke='%23000' stroke-width='2' stroke-linejoin='round'%3E%3Cpath d='M0 -100 86.603 -50 86.603 50 0 100 -86.603 50 -86.603 -50Z'/%3E%3Cpath d='M173.205 -100 259.808 -50 259.808 50 173.205 100 86.603 50 86.603 -50Z'/%3E%3Cpath d='M86.603 50 173.205 100 173.205 200 86.603 250 0 200 0 100Z'/%3E%3Cpath d='M0 200 86.603 250 86.603 350 0 400 -86.603 350 -86.603 250Z'/%3E%3Cpath d='M173.205 200 259.808 250 259.808 350 173.205 400 86.603 350 86.603 250Z'/%3E%3C/g%3E%3Cg fill='%23000'%3E%3Ccircle cx='86.603' cy='50' r='7'/%3E%3Ccircle cx='0' cy='100' r='7'/%3E%3Ccircle cx='173.205' cy='100' r='7'/%3E%3Ccircle cx='0' cy='200' r='7'/%3E%3Ccircle cx='173.205' cy='200' r='7'/%3E%3Ccircle cx='86.603' cy='250' r='7'/%3E%3C/g%3E%3C/svg%3E");
}

/* Pads at every junction. One class, because the tile is the only thing that
   changes -- scale, fade, side and colour all still come from the lattice. */
.hex-field--circuit { --hex-lattice: var(--hex-circuit); }

/*
  The travelling pulse. A child of the field, so the field's mask clips it to the
  traces: the light appears to run along the board rather than over it.

  Deliberately slow and sparse. A 7-second sweep reads as a system ticking over;
  anything faster reads as a loading screen, and this sits behind text that
  people are trying to read.
*/
.hex-pulse {
  position: absolute;
  inset: -30% -70%;
  display: block;
  background: linear-gradient(100deg,
                transparent 42%,
                color-mix(in oklab, var(--hex-accent, #00AAD3) 70%, white) 50%,
                transparent 58%);
  opacity: .9;
  animation: hexSweep 7s cubic-bezier(.55, 0, .45, 1) infinite;
  will-change: transform;
}

@keyframes hexSweep {
  from { transform: translate3d(-42%, 0, 0); }
  to   { transform: translate3d(42%, 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  /* Removed, not paused: a bright bar frozen across the field is worse than no
     effect, because it reads as a rendering fault rather than as decoration. */
  .hex-pulse { display: none; }
}
