/* =====================================================================
   eq-fx.css — the reactive layer
   ---------------------------------------------------------------------
   Loads AFTER eq-system.css. eq-system.css is the foundation and the
   correction layer for everything beneath it; this sheet is additive on
   top of that foundation and owns exactly one thing: surfaces that
   respond to the pointer, and the two marketing pages that earn the
   most from it.

   Every rule here is keyed on a custom property that only `eq-fx.js`
   ever sets (`--eq-sk`, `--eq-rx`, `--eq-mx`, `--eq-rail`) or on markup
   only it ever creates (`.eq-scene`, `data-eq-spot`).
   That is deliberate: if the script fails to load, is blocked, or is
   still downloading, every one of these effects resolves to its
   fallback — 0 opacity, 0 degrees, 0 pixels — and the page is exactly
   the page it was before. Nothing here is load-bearing.

   Contents
     1  Opening scene
     2  Pointer sheen
     3  Reactive edge
     4  Tilt
     5  Magnetic controls
     6  Scroll-linked rail
     7  Odometers
     8  Business / Enterprise components
     9  Landing components
    10  Motion policy
   ===================================================================== */

:root {
  --eq-fx-mint: 141, 227, 187;
  --eq-fx-accent: 63, 207, 155;
  --eq-fx-gold: 231, 192, 120;
  /* One easing for every pointer-driven fade, so a card, a button and a
     table row all feel like the same material. */
  --eq-fx-ease: cubic-bezier(0.16, 1, 0.3, 1);
}

/* =====================================================================
   1. The opening scene
   ---------------------------------------------------------------------
   An orbital system: exchanges and pairs circling the EQ chip. The
   runtime builds the rings, the links and the coins; this owns the
   staging.

   Three nested elements per coin, one transform each — depth and drift
   on the outer (written by the loop), entrance on the middle, rotation
   on the inner. Composing them into a single `transform` would mean
   whichever ran last silently deleted the other two.
   ===================================================================== */

.eq-scene-mount {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  contain: layout paint;
}

.eq-scene {
  position: absolute;
  inset: 0;
}

/* -- Coins -----------------------------------------------------------------
   ONE shared 3D space. `perspective` lives on the scene, not on each
   coin, so every coin is projected through the same vanishing point:
   a nearer coin is genuinely larger, parallaxes further, and can pass in
   front of a further one. When each coin carried its own
   `perspective()` they were five independent little dioramas that
   happened to be different sizes — the arrangement never read as depth
   because there was no shared space for it to be depth in.

   Everything between `.eq-scene` and `.eq-coin__body` must therefore
   keep `transform-style: preserve-3d` and must NOT take `opacity`,
   `filter`, `overflow` or a mask — each of those forces a flattened
   rendering context and collapses the whole chain. That constraint is
   why the entrance is transform-only (coins fly in from far Z rather
   than fading in) and why the depth-of-field blur is applied to the
   faces at the bottom of the chain instead of to the coin. */
.eq-scene {
  perspective: 1150px;
  perspective-origin: 50% 50%;
  transform-style: preserve-3d;
}

/* -- Coins -----------------------------------------------------------------
   Position and size are written by the runtime as inline custom
   properties. The `var()` fallbacks below are only what a coin looks
   like in the frame before the first layout runs.

   That reverses what this file used to do, and the reversal is the
   point. An earlier pass set layout inline from JS and every breakpoint
   below was silently dead, because an inline custom property beats any
   stylesheet rule that is not `!important`; the fix then was to move
   layout into CSS. It cannot live here now: the correct CSS position of
   a coin depends on its place on its orbit and on the size of the scene
   box, which CSS cannot compute. So JS owns layout completely —
   breakpoints included, in `layoutScene` — and
   re-runs on resize. One owner either way; the bug was ever having two.

   What is still CSS is everything about the coin as an OBJECT: its
   thickness, its material, its motion chain. */
.eq-coin {
  position: absolute;
  left: var(--eq-cx, 50%);
  top: var(--eq-cy, 50%);
  width: var(--eq-cw, 150px);
  aspect-ratio: 1;
  margin: calc(var(--eq-cw) / -2) 0 0 calc(var(--eq-cw) / -2);
  transform-style: preserve-3d;
  will-change: transform;
  /* Thickness. A real coin is about 6% of its diameter; a touch more
     reads better here because the rim is what proves the solid. */
  --eq-ct: calc(var(--eq-cw, 150px) * 0.08);
}

.eq-coin__in {
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transform: translate3d(var(--eq-fx), var(--eq-fy), -820px);
}

/* The entrance only runs once the runtime has added `is-in`, a frame
   after the coins are in the document with their from-state applied.
   Without that wait the first coin skips its arrival. */
.eq-scene.is-in .eq-coin__in {
  animation: eq-coin-in 1400ms cubic-bezier(0.16, 1, 0.3, 1) var(--eq-cd) both;
}

/* No `opacity` anywhere in this animation — see the note above. The
   coins arrive out of the depth of the scene instead of fading up, which
   is both a better entrance and the only one the 3D context allows. */
@keyframes eq-coin-in {
  from { transform: translate3d(var(--eq-fx), var(--eq-fy), -820px); }
  to   { transform: translate3d(0, 0, 0); }
}

/* -- The solid --------------------------------------------------------
   A real cylinder: two circular faces and a rim of 40 strips wrapped
   around the edge. `--eq-spin` turns it about the vertical axis and
   `--eq-tiltx` about the horizontal one; two axes at unrelated rates is
   what stops the motion reading as a turntable. */
.eq-coin__body {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transform:
    rotateX(var(--eq-tiltx, 0deg))
    rotateY(var(--eq-spin, 0deg))
    scale(calc(1 + var(--eq-lift, 0) * 0.05));
  will-change: transform;
}

.eq-coin__face {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  /* Without this you see the front face through the back of the coin. */
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

.eq-coin__face svg {
  display: block;
  width: 100%;
  height: 100%;
}

/* The moving highlight. The SVG paints a fixed sweep that turns with the
   metal; this one is offset by −sin(spin) from the runtime, so it walks
   back across the disc as the coin rotates and stays anchored to the
   lamp. No blend mode: `mix-blend-mode` forces a flattened rendering
   context and would collapse the coin's 3D. */
.eq-coin__face--front::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  pointer-events: none;
  background:
    radial-gradient(38% 30% at calc(38% + var(--eq-spec, 0%)) 26%,
                    rgba(255, 255, 255, 0.42), rgba(255, 255, 255, 0.07) 46%, transparent 72%);
}

/* Half the thickness in each direction, so the rim is centred on the
   plane the faces are measured from. */
.eq-coin__face--front { transform: translateZ(calc(var(--eq-ct) / 2)); }
.eq-coin__face--back  { transform: rotateY(180deg) translateZ(calc(var(--eq-ct) / 2)); }

.eq-coin__rim {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}

/* One strip of the milled edge. `rotateZ` puts it at its angle on the
   disc, `translateX` pushes it out to the radius, and `rotateY(90deg)`
   turns it to face radially outward — which is what maps the strip's
   width onto the coin's thickness and its height onto the arc. The
   height carries a few percent of overlap so the seams do not show as
   hairlines when the coin is edge-on. */
.eq-coin__rim i {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--eq-ct);
  height: calc(var(--eq-cw) * 0.0825);
  margin: calc(var(--eq-cw) * -0.04125) 0 0 calc(var(--eq-ct) / -2);
  transform: rotateZ(var(--a)) translateX(calc(var(--eq-cw) / 2 - 0.5px)) rotateY(90deg);
}

/* Grab affordance. Pointer events are off for the whole scene mount, so
   the coins are the only thing in it the cursor can reach. */
@media (hover: hover) and (pointer: fine) {
  .eq-coin {
    pointer-events: auto;
    cursor: grab;
    touch-action: none;
  }

  .eq-coin.is-grabbed {
    cursor: grabbing;
  }
}

/* -- The orbit ------------------------------------------------------------
   The system (`.eq-orbit`) is the one element the pointer leans, so it
   must keep `preserve-3d` and take nothing that flattens (opacity,
   filter, overflow). The rings, the gyros and the glow are its children
   but not ancestors of any coin, so they may fade in. Ring sizes and the
   system's lean are written by the runtime. */
.eq-orbit {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}

.eq-orbit__ring {
  position: absolute;
  left: 50%;
  top: 50%;
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.4s var(--eq-fx-ease);
}

.eq-orbit__ring--venues {
  border: 1px solid rgba(141, 227, 187, 0.24);
  box-shadow: 0 0 22px rgba(141, 227, 187, 0.06), inset 0 0 22px rgba(141, 227, 187, 0.05);
}

.eq-orbit__ring--pairs {
  border: 1px dashed rgba(148, 178, 214, 0.20);
}

.eq-scene.is-in .eq-orbit__ring {
  opacity: 1;
}

/* Two great circles around the core, turned by the runtime on different
   axes. Thin enough to read as instrument wire, not as a second object. */
.eq-orbit__gyro {
  position: absolute;
  left: 50%;
  top: 50%;
  border-radius: 50%;
  border: 1.5px solid rgba(141, 227, 187, 0.32);
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.2s var(--eq-fx-ease) 600ms;
}

.eq-orbit__gyro--1 {
  border-color: rgba(151, 187, 255, 0.24);
}

.eq-scene.is-in .eq-orbit__gyro {
  opacity: 1;
}

/* The core's field: pushed behind the chip so the chip sits in it. */
.eq-orbit__glow {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 44%;
  aspect-ratio: 1;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(closest-side,
    rgba(95, 207, 164, 0.20), rgba(95, 207, 164, 0.07) 55%, transparent 100%);
  transform: translate3d(-50%, -50%, -80px);
  animation: eq-core-breathe 5.5s ease-in-out infinite;
}

@keyframes eq-core-breathe {
  0%, 100% { transform: translate3d(-50%, -50%, -80px) scale(1); opacity: 0.85; }
  50%      { transform: translate3d(-50%, -50%, -80px) scale(1.12); opacity: 1; }
}

/* Links from the core to each exchange, and the packets on them. The
   overlay sits flat in the scene's z = 0 plane; see `makeScene`. */
.eq-orbit__links {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.6s var(--eq-fx-ease) 900ms;
}

.eq-scene.is-in .eq-orbit__links {
  opacity: 1;
}

.eq-orbit__link {
  stroke: rgba(141, 227, 187, 0.42);
  stroke-width: 1.2;
  stroke-dasharray: 2 5;
}

/* Depth cue written by the runtime. On the faces, the bottom of the 3D
   chain, because a filter any higher would flatten the coin. */
.eq-scene--orbit .eq-coin__face {
  filter: brightness(var(--eq-dim, 1));
}

.eq-orbit__packet {
  fill: #c6f7e2;
}

/* =====================================================================
   2. Pointer sheen
   ---------------------------------------------------------------------
   A soft light that tracks the cursor across a surface. `--eq-sk` is the
   presence term (0 away, 1 over) and is spring-smoothed by the runtime,
   so the light does not snap on at the boundary of the card.
   ===================================================================== */

[data-eq-spot] {
  position: relative;
}

[data-eq-spot]::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: var(--eq-sk, 0);
  background:
    radial-gradient(
      68% 130% at var(--eq-sx, 50%) var(--eq-sy, 50%),
      rgba(var(--eq-fx-mint), 0.125),
      rgba(var(--eq-fx-mint), 0.038) 44%,
      transparent 78%
    );
  box-shadow:
    inset 0 0 0 1px rgba(var(--eq-fx-mint), 0.20),
    inset 0 0 30px -10px rgba(var(--eq-fx-accent), 0.42);
  transition: opacity 260ms var(--eq-fx-ease);
}

/* The sheen paints behind the content, never over it. Anything the
   reader is meant to read has to sit above the light. */
[data-eq-spot] > * {
  position: relative;
  z-index: 1;
}

/* Two of these surfaces are not cards: the hero's three facts and the
   stats band are bare label/value stacks with no chrome of their own.
   They keep the light and lose the ring, because a one-pixel rectangle
   around them draws a box where the design deliberately has none. */
.biz-stat[data-eq-spot]::after,
.biz-meta-card[data-eq-spot]::after {
  box-shadow: none;
}

/* =====================================================================
   3. Reactive edge
   ---------------------------------------------------------------------
   A one-pixel gradient ring whose bright point sits under the cursor, so
   the card's own border lights up where you are touching it. Drawn with
   the mask-composite ring trick rather than a border-image, because it
   has to inherit an arbitrary `border-radius` from whatever card it is
   attached to.

   The selector list is explicit rather than `[data-eq-spot]` on purpose:
   these are the classes whose `::before` is verifiably unused in
   landing.css. `.biz-timeline-step` and `.market-mover-card` already own
   theirs and are deliberately absent.
   ===================================================================== */

.biz-card[data-eq-spot]::before,
.biz-tile[data-eq-spot]::before,
.biz-item[data-eq-spot]::before,
.biz-cap-card[data-eq-spot]::before,
.biz-tailored-card[data-eq-spot]::before,
.biz-driver-card[data-eq-spot]::before,
.biz-sdk-card[data-eq-spot]::before,
.biz-faq-item[data-eq-spot]::before,
.feature-card[data-eq-spot]::before,
.pricing-card[data-eq-spot]::before,
.engine-gate[data-eq-spot]::before {
  content: "";
  position: absolute;
  inset: -1px;
  z-index: 0;
  padding: 1px;
  border-radius: inherit;
  pointer-events: none;
  opacity: var(--eq-sk, 0);
  background:
    radial-gradient(
      48% 110% at var(--eq-sx, 50%) var(--eq-sy, 50%),
      rgba(var(--eq-fx-mint), 0.92),
      rgba(var(--eq-fx-gold), 0.34) 46%,
      transparent 78%
    );
  -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;
  transition: opacity 260ms var(--eq-fx-ease);
}

/* =====================================================================
   4. Tilt
   ---------------------------------------------------------------------
   Reserved for the two hero instruments. `--eq-rx` / `--eq-ry` are
   capped at five degrees by the runtime; past that the type on the panel
   shears and the depth stops being free.
   ===================================================================== */

[data-eq-tilt] {
  position: relative;
  transform-style: preserve-3d;
}

/* The class is added on pointer enter and removed once the spring has
   settled back to zero, and the transform is `!important`.

   Both halves of that are load-bearing. `.biz-hero-panel` carries
   `.biz-reveal`, whose reveal is a CSS *animation* with `forwards` — and
   an animation's computed transform beats a normal declaration, so the
   plain rule was being silently discarded (measured: `--eq-rx` set to
   1.4deg, computed transform still the identity matrix). `!important`
   wins that contest. But applying it unconditionally would also override
   the reveal's own `translateY`, so the element would never slide in.
   Scoping the important rule to the hovered state — which can only
   happen long after the reveal has finished — keeps both. */
[data-eq-tilt].eq-tilt-on {
  transform:
    perspective(1400px)
    rotateX(var(--eq-rx, 0deg))
    rotateY(var(--eq-ry, 0deg))
    translateZ(0) !important;
  will-change: transform;
}

/* Lift and a directional shadow, so the object reads as leaving the page
   rather than as a flat rectangle being skewed. */
[data-eq-tilt]::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: calc(var(--eq-tk, 0) * 0.9);
  background:
    linear-gradient(
      calc(180deg + var(--eq-ry, 0deg) * 12),
      rgba(var(--eq-fx-mint), 0.10),
      transparent 55%
    );
  transition: opacity 300ms var(--eq-fx-ease);
}

/* =====================================================================
   5. Magnetic controls
   ---------------------------------------------------------------------
   The button leans a few pixels toward the cursor before it arrives.
   Translation only — never scale, which would move the hit target out
   from under a pointer that is already on its way.
   ===================================================================== */

[data-eq-magnet] {
  transform: translate3d(var(--eq-mx, 0px), var(--eq-my, 0px), 0);
}

/* The lean has to *compose* with the lift the button already had.
   `.btn-primary-custom:hover` and `.btn-outline-custom:hover` both set
   `transform: translateY(-2px)`, at a specificity the bare attribute
   selector loses to — so without these the magnet measured correctly in
   its custom properties and did nothing on screen. Folding the -2px into
   the same translate keeps the original hover and adds the lean, instead
   of one silently deleting the other. */
.btn[data-eq-magnet]:hover,
.btn[data-eq-magnet]:focus-visible {
  transform: translate3d(var(--eq-mx, 0px), calc(var(--eq-my, 0px) - 2px), 0);
}

.btn[data-eq-magnet]:active {
  transform: translate3d(var(--eq-mx, 0px), var(--eq-my, 0px), 0) scale(0.98);
}

/* The lean must not fight the focus ring: outline is drawn on the
   element's own box, which moves with it, so the ring stays attached.
   The transform is added to whatever transition the button already had
   — eq-system.css already narrowed `transition-property` on `.btn` away
   from `all`, and `transform` is in that list. */

/* =====================================================================
   6. Scroll-linked rail
   ---------------------------------------------------------------------
   `--eq-rail` runs 0 → 1 across the reading of the block it is set on.
   ===================================================================== */

.biz-timeline-grid[data-eq-rail] {
  position: relative;
}

/* The lit portion of the connector, laid over the static rule the
   timeline already draws. */
.biz-timeline-grid[data-eq-rail]::after {
  content: "";
  position: absolute;
  top: 5px;
  left: 0;
  z-index: 1;
  width: calc(var(--eq-rail, 0) * 100%);
  height: 1px;
  background: linear-gradient(90deg, var(--eq-accent), var(--biz-gold, #e7c078));
  box-shadow: 0 0 12px rgba(var(--eq-fx-accent), 0.55);
  pointer-events: none;
}

/* Each node fills as the rail reaches it. The thresholds are the four
   quarter points, widened slightly so a node is lit a moment before the
   line technically arrives — otherwise the dot always looks late. */
.biz-timeline-grid[data-eq-rail] .biz-timeline-step:nth-child(1) { --eq-node: clamp(0, calc((var(--eq-rail, 0) - 0.02) * 14), 1); }
.biz-timeline-grid[data-eq-rail] .biz-timeline-step:nth-child(2) { --eq-node: clamp(0, calc((var(--eq-rail, 0) - 0.24) * 14), 1); }
.biz-timeline-grid[data-eq-rail] .biz-timeline-step:nth-child(3) { --eq-node: clamp(0, calc((var(--eq-rail, 0) - 0.49) * 14), 1); }
.biz-timeline-grid[data-eq-rail] .biz-timeline-step:nth-child(4) { --eq-node: clamp(0, calc((var(--eq-rail, 0) - 0.74) * 14), 1); }

.biz-timeline-grid[data-eq-rail] .biz-timeline-step::after {
  z-index: 2;
  background: color-mix(in srgb, var(--eq-accent) calc(var(--eq-node, 0) * 100%), var(--primary-dark));
  box-shadow: 0 0 calc(var(--eq-node, 0) * 15px) rgba(var(--eq-fx-accent), 0.6);
}

.biz-timeline-grid[data-eq-rail] .biz-timeline-week {
  opacity: calc(0.5 + var(--eq-node, 0) * 0.5);
  transition: opacity 320ms var(--eq-fx-ease);
}

/* =====================================================================
   7. Odometers
   ---------------------------------------------------------------------
   The runtime rewrites the numeric run inside these elements while they
   count. Tabular figures keep the box from reflowing on every frame,
   which is what makes a counting number feel like a readout rather than
   a wobble.
   ===================================================================== */

[data-eq-odometer] {
  font-variant-numeric: tabular-nums slashed-zero;
  font-feature-settings: "tnum" 1, "zero" 1;
}

/* =====================================================================
   8. Business / Enterprise components
   ===================================================================== */

/* -- Section index ---------------------------------------------------------
   The landing page numbers its argument (`eq-index`, 01 → 07). The
   business page made the same argument in the same order and did not,
   so a reader could not tell how far through it they were. The counter
   is CSS-side: no copy to translate, no markup to keep in sync, and it
   renumbers itself if a section is ever added or dropped. */
.biz-landing {
  counter-reset: biz-section;
}

.biz-section {
  position: relative;
}

/* `:has(h2)` is the test because the index numbers the page's *argument*
   — the sections that stand up and make a claim. The deployment options
   block has no heading; it is an appendix, and giving it a number would
   promote it to a step in a sequence it is not part of. Putting the
   increment on the same selector as the number is what keeps the run
   contiguous: an earlier version incremented per section and displayed
   on a subset, which produced 01 02 03 __ 05 — worse than not numbering.

   Two of these containers are laid out as a grid (`biz-deploy-grid`,
   `biz-integrations-grid`), and generated content in a grid container
   would normally become a grid *item* and push empty cells into the
   layout. An out-of-flow box is not a grid item, though, and both boxes
   below are `position: absolute` — verified in the browser: the deploy
   grid still resolves to exactly three tracks with three items in them.

   If `:has()` is unsupported the whole block drops and the page simply
   has no section numbers, which is the pre-existing design. */
.biz-section > .container:has(h2) {
  position: relative;
  counter-increment: biz-section;
}

.biz-section > .container:has(h2)::before {
  content: counter(biz-section, decimal-leading-zero);
  position: absolute;
  top: -1.9em;
  left: 0;
  font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
  font-size: var(--eq-text-2xs);
  font-weight: 700;
  letter-spacing: var(--eq-tracking-label);
  color: rgba(var(--eq-fx-mint), 0.42);
}

/* A hairline running from the index into the section, borrowing the
   home page's `eq-index__rule` idea without importing its markup. */
.biz-section > .container:has(h2)::after {
  content: "";
  position: absolute;
  top: calc(-1.9em + 0.45em);
  left: 2.6em;
  width: clamp(2rem, 6vw, 5rem);
  height: 1px;
  background: linear-gradient(90deg, rgba(var(--eq-fx-mint), 0.34), transparent);
}

/* -- Hero risk console -----------------------------------------------------
   The four rows in the hero panel are the product's risk envelope. They
   were four label/value pairs; a gauge behind each value turns the panel
   into the instrument the copy says it is. `data-eq-gauge` is a plain
   decimal in the markup and carries no meaning a reader depends on —
   the number beside it is still the fact. */
.biz-panel-row[data-eq-gauge] {
  position: relative;
  overflow: hidden;
}

/* Track. */
.biz-panel-row[data-eq-gauge]::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: rgba(255, 255, 255, 0.055);
}

/* Fill. Painted after the track in tree order, which is what puts it on
   top — the row has an opaque background, so a negative z-index would
   bury both. */
.biz-panel-row[data-eq-gauge]::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  height: 2px;
  width: calc(var(--eq-gauge, 0) * 100%);
  background: linear-gradient(90deg, rgba(var(--eq-fx-accent), 0.75), rgba(var(--eq-fx-gold), 0.55));
  border-radius: 2px;
  transform-origin: left center;
  animation: eq-gauge-in 900ms var(--eq-fx-ease) both;
}

@keyframes eq-gauge-in {
  from { transform: scaleX(0); opacity: 0; }
  to   { transform: scaleX(1); opacity: 1; }
}

/* -- Stats band ------------------------------------------------------------
   Four numbers on one line read as a wall. Giving each a column rule and
   letting the value light on approach makes it a readout. */
/* The column rule. `.biz-stats-grid` already draws a hairline across the
   top of the band; a rule down the left of each figure turns four
   numbers sharing a line into four readings, each in its own channel. */
.biz-stat {
  position: relative;
  padding-left: var(--eq-space-5, 1.25rem);
  border-left: 1px solid var(--eq-edge, rgba(211, 223, 236, 0.16));
  transition: border-color 280ms var(--eq-fx-ease);
}

.biz-stat:hover {
  border-left-color: rgba(var(--eq-fx-accent), 0.55);
}

/* The hero's three facts are the same kind of object as a stat, so they
   are drawn the same way rather than inventing a second treatment. */
.biz-meta-card {
  position: relative;
  /* Tighter than the stats band's channel: these three sit in a narrower
     grid and a full 1rem of indent pushed "Per-tenant envelope keys" onto
     a second line. */
  padding-left: var(--eq-space-3, 0.75rem);
  border-left: 1px solid var(--eq-edge, rgba(211, 223, 236, 0.16));
  transition: border-color 280ms var(--eq-fx-ease);
}

.biz-meta-card:hover {
  border-left-color: rgba(var(--eq-fx-accent), 0.55);
}

.biz-stat[data-eq-spot]::before {
  /* A square ring, not a rounded one: the stat has no card around it. */
  border-radius: 0;
}

.biz-stat > .biz-stat-value {
  transition: color 320ms var(--eq-fx-ease), text-shadow 320ms var(--eq-fx-ease);
}

.biz-stat:hover > .biz-stat-value {
  color: var(--eq-accent-strong, #8de3bb);
  text-shadow: 0 0 22px rgba(var(--eq-fx-accent), 0.35);
}

/* -- Build vs buy ----------------------------------------------------------
   The table's whole job is to make one column look like the answer. It
   was three columns of equal weight, so it did not. The "buy" column now
   sits on a surface and the "build" column recedes; hovering a row
   raises the comparison being read. */
.biz-compare-row[data-eq-spot] {
  transition: background-color 240ms var(--eq-fx-ease);
}

.biz-compare-row[data-eq-spot]:hover {
  background-color: rgba(var(--eq-fx-mint), 0.035);
}

.biz-compare-table .biz-compare-buy {
  position: relative;
}

.biz-compare-row:not(.biz-compare-head) .biz-compare-build {
  color: var(--eq-muted-ink, rgba(200, 216, 226, 0.62));
}

.biz-compare-row:not(.biz-compare-head) .biz-compare-buy {
  background: linear-gradient(180deg, rgba(var(--eq-fx-accent), 0.055), rgba(var(--eq-fx-accent), 0.02));
  box-shadow: inset 1px 0 0 rgba(var(--eq-fx-accent), 0.22);
}

.biz-compare-head .biz-compare-buy {
  color: var(--eq-accent-strong, #8de3bb);
}

/* -- Integration code block ------------------------------------------------
   Window chrome, so the snippet reads as a thing you run rather than a
   quotation. Drawn entirely in CSS — no extra markup, nothing to
   translate, and it disappears cleanly on a narrow screen. */
.biz-code {
  position: relative;
  padding-top: calc(var(--eq-space-4) + 1.75rem);
}

.biz-code::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1.75rem;
  border-bottom: 1px solid var(--eq-edge, rgba(211, 223, 236, 0.16));
  background: rgba(255, 255, 255, 0.028);
  border-radius: var(--eq-radius-tile, 10px) var(--eq-radius-tile, 10px) 0 0;
}

.biz-code::after {
  content: "";
  position: absolute;
  top: 0.72rem;
  left: 0.85rem;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(var(--eq-fx-accent), 0.75);
  box-shadow:
    12px 0 0 rgba(var(--eq-fx-gold), 0.55),
    24px 0 0 rgba(255, 255, 255, 0.18);
}

/* -- Capability and tailored cards ----------------------------------------
   These were flat blocks in a grid. A leading rule that fills on hover
   gives the grid a reading order and gives the pointer something to
   answer to. */
.biz-cap-card,
.biz-tailored-card,
.biz-driver-card {
  position: relative;
  overflow: hidden;
}

.biz-cap-card > .biz-cap-title,
.biz-tailored-card > h4,
.biz-driver-card > h4 {
  position: relative;
}

/* -- Closing call to action ------------------------------------------------ */
.biz-cta {
  position: relative;
  overflow: hidden;
}

.biz-cta > .container {
  position: relative;
  z-index: 1;
}

/* =====================================================================
   9. Landing components
   ===================================================================== */

/* The hero already layers a gradient and an animated lattice in
   the hero's flat gradient surface. */
.hero-section {
  isolation: isolate;
}

.hero-section > .container {
  position: relative;
  z-index: 1;
}

.cta-section {
  position: relative;
  overflow: hidden;
}

.cta-section > .container {
  position: relative;
  z-index: 1;
}

/* The hero instrument gets the tilt, so its bezel needs a shadow that
   deepens with the lean rather than a static one. */
.hero-terminal[data-eq-tilt] {
  transition: box-shadow 320ms var(--eq-fx-ease);
}

.hero-terminal[data-eq-tilt]:hover {
  box-shadow:
    0 34px 70px -30px rgba(0, 0, 0, 0.75),
    0 0 0 1px rgba(var(--eq-fx-mint), 0.16);
}

.biz-hero-panel[data-eq-tilt] {
  transition: box-shadow 320ms var(--eq-fx-ease);
}

.biz-hero-panel[data-eq-tilt]:hover {
  box-shadow:
    0 30px 64px -28px rgba(0, 0, 0, 0.72),
    0 0 0 1px rgba(var(--eq-fx-mint), 0.16);
}

/* Trust chips light individually rather than as a row. */
.trust-chip[data-eq-spot]::after {
  box-shadow: inset 0 0 0 1px rgba(var(--eq-fx-mint), 0.26);
}

/* =====================================================================
   10. Motion policy
   ---------------------------------------------------------------------
   The reduced-motion contract for this layer: the art stays, the motion
   stops. The scene settles into its composed frame and the loop parks;
   tilt and magnetism resolve to zero in the runtime, and are pinned to
   zero here as well so a stale custom property left over from before the
   preference changed cannot keep an element skewed.
   ===================================================================== */

@media (prefers-reduced-motion: reduce) {
  [data-eq-tilt],
  [data-eq-tilt].eq-tilt-on {
    transform: none !important;
  }

  [data-eq-magnet] {
    transform: none !important;
  }

  /* The scene keeps its composition and loses its motion: the coins are
     placed where the entrance would have left them, and neither the
     arrival nor the drift ever runs. The drift and the idle spin are
     separately pinned to zero in the runtime. */
  .eq-scene .eq-coin__in {
    transform: none;
    transition: none;
  }

  .eq-scene.is-in .eq-coin__in {
    animation: none;
  }

  /* `.eq-coin` is deliberately NOT reset either. Its transform is the
     coin's place on its orbit — blanking it would stack every coin on
     the core. The runtime freezes the orbit under this preference
     instead; the arrangement is composition, not motion, and it stays. */

  /* `.eq-coin__body` is deliberately NOT reset. It carries the coin's
     resting angle and its perspective, so zeroing it here would flatten
     five solids into five flat discs — which is removing the art, not
     the motion. The runtime holds the idle spin rate at zero instead. */

  [data-eq-spot]::after,
  [data-eq-spot]::before {
    transition: none;
  }

  .biz-panel-row[data-eq-gauge]::after {
    animation: none;
  }
}

/* Coarse pointers keep the scene and the rail — both of which are driven
   by scroll — and lose the hover choreography, which has nothing to
   respond to on a touchscreen and only costs a paint. */
@media (hover: none), (pointer: coarse) {
  [data-eq-tilt],
  [data-eq-tilt].eq-tilt-on {
    transform: none !important;
  }

  [data-eq-magnet] {
    transform: none;
  }
}

/* Below the business page's three-column breakpoint the timeline stacks,
   so a horizontal rail across the top of it would be pointing at
   nothing. */
@media (max-width: 900px) {
  .biz-timeline-grid[data-eq-rail]::after {
    display: none;
  }

  .biz-section > .container:has(h2)::after {
    display: none;
  }
}
