/* iso-accents v51 */
/* Iso-plate accents — lanes, terminals and the gestures that go with them.
 *
 * An opt-in layer on top of assets/iso-plate.css. A stage asks for it by
 * carrying the attribute and nothing else changes anywhere:
 *
 *     <div class="iso-stage-3" data-iso-lanes>          <!-- mix, one per plate -->
 *     <div class="iso-stage"   data-iso-lanes="f">      <!-- one named scheme -->
 *
 * Every selector below is scoped to that attribute, so a page that does not use
 * it renders exactly as it did before this file existed. assets/js/iso-accents.js
 * draws the lanes and drives the two gestures; without it a marked stage is a
 * plain stage, because everything here needs markup that script puts in.
 *
 * What it adds, in the order the rules come:
 *   1. The fade moves from the stage onto a deck around the plates, so the
 *      decoration can be drawn outside it.
 *   2. A shorter stack, and a stack at rest that is not pre-answered.
 *   3. Hover picks the front plate of a stack; click blows one up and lets the
 *      pointer explore it.
 *   4. The decoration itself, and the build that brings it in.
 *
 * Every number is a custom property with the shipped value as its fallback, so
 * a page - or iso-lab.html - can move one without forking a rule.
 */

/* ---- 1 · the deck -------------------------------------------------------
   The stage fade is a group fade: the plates composite first and the whole
   group then dissolves. It cannot stay on the stage, because a mask takes its
   element's entire subtree with it and the lanes would dissolve along with the
   picture they point at. Putting it on each fly instead is worse: every plate
   then fades on its own and they print through each other where they overlap.
   So the flies are wrapped in a deck - iso-accents.js does it, no page has to
   author it - and the deck carries the mask. The decoration sits beside the
   deck, outside the mask, and behind it. */
#top [data-iso-lanes]{-webkit-mask-image:none;mask-image:none}

/* The fade is one parametric mask whose stops are registered custom properties,
   and that sentence is the fix for the last of the exit twitches.

   A mask-image cannot be transitioned: swap it and the change lands in a single
   frame. This component needs two fades - the resting slab, solid to 40% of the
   band and dissolved by the bottom, and the reading window, solid nearly to the
   edges - and as two mask-images every crossing between them was a visible cut.
   Holding the swap until "the motion is over" only moved the cut: the resting
   plate stands almost the full height of the band, so its lower half sits deep
   in the resting fade, and the swap dimmed half the picture in one frame
   whenever it came.

   Registered with @property, a custom property has a type, and a typed property
   interpolates. The stops move, the browser re-resolves the gradient each
   frame, and the fade between the two looks is a fade. The is-settling and
   is-landing holds stay, but they are no longer load-bearing: whenever the
   window lets go, it lets go over half a second. Browsers without @property
   fall back to the old behaviour - the values still apply, they just cut. */
@property --iso-m-top { syntax:'<percentage>'; inherits:false; initial-value:0%; }
@property --iso-m-b1  { syntax:'<percentage>'; inherits:false; initial-value:40%; }
@property --iso-m-b2  { syntax:'<percentage>'; inherits:false; initial-value:66%; }
@property --iso-m-b3  { syntax:'<percentage>'; inherits:false; initial-value:86%; }
@property --iso-m-l1  { syntax:'<percentage>'; inherits:false; initial-value:2%; }
@property --iso-m-l2  { syntax:'<percentage>'; inherits:false; initial-value:7%; }
@property --iso-m-r2  { syntax:'<percentage>'; inherits:false; initial-value:93%; }
@property --iso-m-r1  { syntax:'<percentage>'; inherits:false; initial-value:98%; }

#top [data-iso-lanes] > .iso-deck{
  position:absolute;
  inset:0;
  /* The resting stops. The two shade knobs keep working: a calc over an
     unregistered var still computes to a plain percentage, which is what the
     registered property stores and interpolates. */
  --iso-m-top:0%;
  --iso-m-b1:calc(var(--iso-shade,40) * 1%);
  --iso-m-b2:calc(var(--iso-shade,40) * 1% + 26%);
  --iso-m-b3:calc(var(--iso-shade,40) * 1% + 46%);
  --iso-m-l1:2%;--iso-m-l2:7%;--iso-m-r2:93%;--iso-m-r1:98%;
  -webkit-mask-composite:source-in;
  mask-composite:intersect;
  -webkit-mask-image:
    linear-gradient(to bottom,transparent 0,#000 var(--iso-m-top),#000 var(--iso-m-b1),rgba(0,0,0,.55) var(--iso-m-b2),rgba(0,0,0,.2) var(--iso-m-b3),transparent 100%),
    linear-gradient(to right,transparent 0,rgba(0,0,0,.5) var(--iso-m-l1),#000 var(--iso-m-l2),#000 var(--iso-m-r2),rgba(0,0,0,.5) var(--iso-m-r1),transparent 100%);
  mask-image:
    linear-gradient(to bottom,transparent 0,#000 var(--iso-m-top),#000 var(--iso-m-b1),rgba(0,0,0,.55) var(--iso-m-b2),rgba(0,0,0,.2) var(--iso-m-b3),transparent 100%),
    linear-gradient(to right,transparent 0,rgba(0,0,0,.5) var(--iso-m-l1),#000 var(--iso-m-l2),#000 var(--iso-m-r2),rgba(0,0,0,.5) var(--iso-m-r1),transparent 100%);
  transition:--iso-m-top .4s cubic-bezier(.37,0,.63,1),--iso-m-b1 .4s cubic-bezier(.37,0,.63,1),
             --iso-m-b2 .4s cubic-bezier(.37,0,.63,1),--iso-m-b3 .4s cubic-bezier(.37,0,.63,1),
             --iso-m-l1 .4s cubic-bezier(.37,0,.63,1),--iso-m-l2 .4s cubic-bezier(.37,0,.63,1),
             --iso-m-r2 .4s cubic-bezier(.37,0,.63,1),--iso-m-r1 .4s cubic-bezier(.37,0,.63,1);
}

/* A plate that is up is being read, so the band opens into a window: solid to
   within a few percent of every edge. Same mask, different numbers - which is
   the whole point, because moving numbers is a motion and swapping images was
   a cut. */
#top [data-iso-lanes].has-zoom > .iso-deck,
#top [data-iso-lanes].is-settling > .iso-deck,
#top [data-iso-lanes].is-landing > .iso-deck{
  --iso-m-top:5%;--iso-m-b1:92%;--iso-m-b2:96%;--iso-m-b3:98%;
  --iso-m-l1:2%;--iso-m-l2:4%;--iso-m-r2:96%;--iso-m-r1:98%;
  /* The mask expression again, verbatim - redundant against this file alone,
     load-bearing against its own past. The site bundle carries a copy of this
     stylesheet, rebuilt on another session's cadence, and an older copy's zoom
     rule declared mask-image as a static window literal on this very selector -
     higher specificity than the parametric base above, so the literal held
     while the zoom or a hold was active and vanished in one frame when it let
     go. The cut this file exists to remove, reintroduced by an old edition of
     itself. Restating the parametric image here means the freshest copy in
     document order settles every specificity tier it uses, whatever a stale
     bundle carries. */
  -webkit-mask-image:
    linear-gradient(to bottom,transparent 0,#000 var(--iso-m-top),#000 var(--iso-m-b1),rgba(0,0,0,.55) var(--iso-m-b2),rgba(0,0,0,.2) var(--iso-m-b3),transparent 100%),
    linear-gradient(to right,transparent 0,rgba(0,0,0,.5) var(--iso-m-l1),#000 var(--iso-m-l2),#000 var(--iso-m-r2),rgba(0,0,0,.5) var(--iso-m-r1),transparent 100%);
  mask-image:
    linear-gradient(to bottom,transparent 0,#000 var(--iso-m-top),#000 var(--iso-m-b1),rgba(0,0,0,.55) var(--iso-m-b2),rgba(0,0,0,.2) var(--iso-m-b3),transparent 100%),
    linear-gradient(to right,transparent 0,rgba(0,0,0,.5) var(--iso-m-l1),#000 var(--iso-m-l2),#000 var(--iso-m-r2),rgba(0,0,0,.5) var(--iso-m-r1),transparent 100%);
}

/* ---- 2 · the stack at rest ----------------------------------------------
   A shorter stack than iso-plate.css authors. At the full offset a three-stack
   reads as three separate pictures standing near each other rather than as one
   object with depth. Restated in descendant form, because the deck this file's
   script inserts sits between the stage and its flies and the shipped rules
   name a direct child.

   The depth values ride along even though only the offsets are being changed:
   they come from those same shipped rules, so a marked stage would lose them
   through the deck. That is what makes this file self-sufficient - it needs
   nothing from iso-plate.css that inserting the deck could take away. */
#top [data-iso-lanes].iso-stage-2 .iso-fly:nth-child(1) .iso-plate{--iso-depth:.94;--iso-dy:calc(-50px * var(--iso-spread,.6))}
#top [data-iso-lanes].iso-stage-2 .iso-fly:nth-child(2) .iso-plate{--iso-dy:calc(50px * var(--iso-spread,.6))}
#top [data-iso-lanes].iso-stage-3 .iso-fly:nth-child(1) .iso-plate{--iso-depth:.883;--iso-dy:calc(-105px * var(--iso-spread,.6))}
#top [data-iso-lanes].iso-stage-3 .iso-fly:nth-child(2) .iso-plate{--iso-depth:.94}
#top [data-iso-lanes].iso-stage-3 .iso-fly:nth-child(3) .iso-plate{--iso-dy:calc(105px * var(--iso-spread,.6))}
@media (max-width:1024px){
  #top [data-iso-lanes].iso-stage-2 .iso-fly:nth-child(1) .iso-plate{--iso-dy:calc(-42px * var(--iso-spread,.6))}
  #top [data-iso-lanes].iso-stage-2 .iso-fly:nth-child(2) .iso-plate{--iso-dy:calc(42px * var(--iso-spread,.6))}
  #top [data-iso-lanes].iso-stage-3 .iso-fly:nth-child(1) .iso-plate{--iso-dy:calc(-65px * var(--iso-spread,.6))}
  #top [data-iso-lanes].iso-stage-3 .iso-fly:nth-child(3) .iso-plate{--iso-dy:calc(65px * var(--iso-spread,.6))}
}
/* And at rest none of them recedes. iso-plate.css dims everything that is not
   the front plate, which says which one is being looked at - and until someone
   points at one, that is an answer to a question nobody asked: the plates
   behind read as switched off rather than as stacked. It comes back the moment
   a plate is picked up, where it earns its keep. */
#top [data-iso-lanes]:not(.has-on) .iso-plate>img{filter:none}
#top [data-iso-lanes]:not(.has-on) .iso-plate--lift>img{filter:brightness(1.14) saturate(1.05)}

/* ---- 3 · the two gestures -----------------------------------------------
   The flies stop catching the pointer so the plates can: a fly is inset:0, so
   the topmost one covers the whole stage and would swallow every hover meant
   for the sliver of a plate behind it. Transparent is still hit-testable; only
   pointer-events settles it. */
#top [data-iso-lanes] .iso-fly{pointer-events:none}
#top [data-iso-lanes] .iso-plate{pointer-events:auto;cursor:zoom-in}
#top [data-iso-lanes] .iso-deco,
#top [data-iso-lanes] .iso-deco *{pointer-events:none}

/* --fx and --fy are one translate channel with two contributors: where a plate
   sits, and whether it is the one being looked at. They meet in a single
   declaration because a second rule setting `translate` would replace this one
   rather than add to it. */
#top [data-iso-lanes] .iso-fly{
  translate:var(--fx,0px) var(--fy,0px);
  /* The rise used to ride the 620ms crossfade clock and read as sluggish for
     a 22px move; it gets its own, quicker one. Opacity and filter stay on the
     switch clock - they are the stack crossfade and were never the complaint. */
  transition:opacity calc(var(--iso-sw-ms,620) * 1ms) ease,
             filter calc(var(--iso-sw-ms,620) * 1ms) ease,
             translate calc(var(--iso-lift-ms,340) * 1ms) cubic-bezier(.2,.8,.25,1);
}
#top [data-iso-lanes] .iso-fly.is-on{z-index:4;--fy:calc(var(--iso-rise,22) * -1px)}
#top [data-iso-lanes] .iso-fly.is-on .iso-plate>img{filter:none}
#top [data-iso-lanes].iso-stage-2.has-on .iso-fly:not(.is-on):not(.iso-deco),
#top [data-iso-lanes].iso-stage-3.has-on .iso-fly:not(.is-on):not(.iso-deco){opacity:.34;filter:saturate(.6)}

/* One screenshot has no stack to switch, so the same gesture collapses into it:
   it rises and peeks. Keyed on the plate being hovered rather than the stage,
   because the stage box is a good deal larger than the picture in it and the
   band around it is exactly where a pointer passes on its way somewhere else. */
/* Driven by a class, not by :hover, and the reason is a loop.

   The lift moves the plate 22px up and the peek grows it 6%, which nets a
   bottom edge that sits 10px higher than it did at rest - measured on the lab
   page, 590 to 580. With the state keyed on the plate itself, a pointer inside
   that 10px band triggered the lift, the plate travelled out from under it,
   the hover dropped, the plate came back down onto the pointer, and it started
   again. A hit target that moves because it was hit cannot settle.

   The class comes from iso-accents.js, which arms it on the plate and clears
   it on the stage. Entering stays exact - the band around a stage is where a
   pointer passes on its way somewhere else, and it must not lift anything -
   but leaving is judged against the stage box, which is stationary and far
   larger than the travel. So the lift can never push the pointer out of the
   region that holds it up. */
#top [data-iso-lanes]:not(.iso-stage-2):not(.iso-stage-3).is-lifted .iso-fly{
  --fy:calc(var(--iso-rise,22) * -1px);
}
#top [data-iso-lanes]:not(.iso-stage-2):not(.iso-stage-3).is-lifted .iso-plate:not(.is-zoom){
  scale:calc(var(--iso-cq,1) * var(--iso-depth,1) * var(--iso-peek,1.06));
}

/* ---- Overrides for the raw-hover era still shipping in the head bundle ---
   The site head links a built bundle whose copy of this file predates the
   is-lifted rework: it lifts and peeks on `.iso-plate:hover` directly, with
   none of the hold logic. Those two rules sit at (1,6,0) - the :has() with a
   compound argument counts two classes - which outranks the (1,5,0) lift
   above, so on the published site they fired on every raw hover flicker. The
   zoom exit is where that showed: a shrinking plate moves under the pointer,
   hover flaps on and off, and the fly jumped its full rise per flap. The lab
   loads no bundle, which is why the twitch was live-only and every lab
   verification of the exit was honestly clean.

   These restate the stale selectors VERBATIM, so they tie them exactly and
   win on sheet order - this file loads from the footer, after the head's
   bundle. The values delegate to variables only the class system writes:
   lifted, they equal what the rules above already compute, so the pair is
   behaviour-neutral the day the bundle is rebuilt from a current checkout and
   the stale rules disappear. Unlifted, they pin the fly down and the scale to
   base, which is the whole correction.

   The settle holds at (1,7,0) still outrank both, unchanged. */
#top [data-iso-lanes]:not(.iso-stage-2):not(.iso-stage-3):has(.iso-plate:hover) .iso-fly{
  --fy:var(--adm-lift-fy,0px);
}
#top [data-iso-lanes]:not(.iso-stage-2):not(.iso-stage-3) .iso-plate:hover:not(.is-zoom){
  scale:calc(var(--iso-cq,1) * var(--iso-depth,1) * var(--adm-lift-peek,1));
}
#top [data-iso-lanes]:not(.iso-stage-2):not(.iso-stage-3).is-lifted{
  --adm-lift-fy:calc(var(--iso-rise,22) * -1px);
  --adm-lift-peek:var(--iso-peek,1.06);
}
/* The bundle's third raw-hover rule, found later than the first two: it
   brightens the decoration on `:has(.iso-plate:hover)` directly, at (1,6,0),
   which outranks the class-driven brightening below. While the plate travels
   its edge sweeps under a resting pointer and the browser flaps hover on and
   off - the lift is held by geometry and does not move, but this rule made
   the lanes pulse bright and dim with every flap. Tied verbatim, delegated
   to a variable only the class system writes: identical when lifted, pinned
   to the resting tone when not. */
#top [data-iso-lanes]:has(.iso-plate:hover) .iso-deco .iso-plate.is-shown{
  opacity:var(--adm-deco-hot,var(--acc-rest,.5));
}
/* The drawing holds still while the plate lifts. The deco is itself an
   .iso-fly and its ghosts are .iso-plate, so the lift's --fy and peek scale
   used to reach them and the whole set of lanes and dots rode 22px up and 6%
   out on every hover - which read as the drawing lurching, not as the picture
   rising. The plate is the thing being offered; the drawing is its footprint
   and stays put, answering the hover with brightness alone. !important
   because the head bundle's raw-hover rule sets --fy at (1,6,0) and this pin
   has to beat it whatever that bundle carries. The settle rules set the same
   0px, so nothing fights on the way down. */
#top [data-iso-lanes] > .iso-deco{--fy:0px !important}
#top [data-iso-lanes] .iso-deco .iso-plate:not(.is-zoom){
  scale:calc(var(--iso-cq,1) * var(--iso-depth,1)) !important;
}
#top [data-iso-lanes].is-lifted,
#top [data-iso-lanes].has-on{
  --adm-deco-hot:var(--acc-tone,1);
}

/* ---- "Click to zoom", a plaque hung off the slab -------------------------
   A real element, built by iso-accents.js as a child of the plate, so it
   inherits the plate's rotateX/rotateZ and lies in the picture's own plane
   rather than floating flat in front of it. Hung off the lower edge and
   entirely clear of the image: a picture with a label across its own border
   reads as part of the screenshot.

   It carries no `button` class and no glitch wrapper. Both were here, so the
   site's hover stutter would run on it, and the stutter is wrong for this:
   the chip names a gesture the picture offers, it is not an action of its
   own - and every tear moved it, which on a label attached to an image reads
   as breakage rather than as texture. */
#top [data-iso-lanes] .iso-cue-host{
  position:absolute;left:50%;bottom:0;z-index:3;
  /* A plaque hanging off the slab's lower edge, in the picture's own plane -
     it inherits the plate's pitch and yaw by being its child, so nothing here
     rotates except the counter-pitch that keeps 9px type readable.

     Three calibrated numbers:
     - the drop hangs the plaque half over the shot's lower edge: its upper
       half overlaps the slab's edge band, its lower half sits on the page
       ground. Chosen by eye in the lab against two other candidates - 115%
       read as lying on the picture, 260% as fully detached from it - and the
       percentage is of the host's own ~20px height, which projects to ~15px
       of screen descent per 100 points at the shipped angles;
     - the small in-plane slide of -.03 x --iso-h centres it on the DRAWN
       bottom edge, which is where the eye measures a label that hangs from
       that edge. An earlier -.29 centred it on the plate's bounding box
       instead - mathematically clean, and visibly wrong: the box centre sits
       72px left of the projected edge midpoint at the shipped angles, so the
       chip read as hanging under the picture's lower-left corner. Compared
       side by side on screenshots before choosing;
     - 24px out along the normal keeps it in front of the image where the two
       overlap on screen, because inside preserve-3d depth decides and z-index
       is ignored.

     transform-origin at the top edge, so the counter-pitch tips the body away
     BELOW the hanging line instead of pivoting around its middle and climbing
     back over the edge it just cleared. */
  transform-origin:50% 0;
  transform:translate(-50%,126%)
            translateX(calc(var(--iso-h) * -.03))
            translateZ(24px)
            rotateX(-22deg);
  transform-style:preserve-3d;
  /* Nothing painted on the host itself - restated here because these two lines
     were lost once in a placement rewrite, and the plate's side-face rule
     (`.iso-plate > span`, the slab faces are spans) immediately dressed the
     host in a grey ground and edge. The host is a div now, so that rule cannot
     match it at all; this is the belt to that braces. */
  background:transparent;
  border:0;
  /* Dead to the pointer, and that is a bug fix rather than a nicety. The
     plaque hangs below the plate's box while being the plate's CHILD, so a
     pointer in that strip hovered the plate through it: the plate lifted, the
     plaque rode up out from under the pointer, the hover dropped, the plate
     came back down onto it - and the frame jittered in the loop. The same
     moving-hit-target failure the lift logic already guards against at the
     plate's own edge, reintroduced by a protruding child. The label is
     aria-hidden and duplicates the plate's own gesture, so it has no claim on
     the pointer at all. */
  pointer-events:none;
  /* Hidden until a plate is up. Lives on this element rather than anything
     built later, so a stage cannot flash its cue during its first frames. */
  opacity:0;
  transition:opacity .2s ease;
}

/* While a plate is being looked at, the deck's fade opens - same stops the
   zoom hold uses, on the same registered properties, so it is the same half
   second cross-fade and the same stale-bundle-proof mechanics. Two jobs in
   one move: the picture someone is actually pointing at deserves its full
   lower half, and the plaque hangs exactly in the band the resting fade
   dims - at rest the mask there is a fifth or less, and a fifth of an
   already-mostly-transparent chip is nothing at all, which is how the label
   managed to be invisible while every measurement said "shown". */
#top [data-iso-lanes].is-lifted > .iso-deck,
#top [data-iso-lanes].has-on > .iso-deck{
  --iso-m-b1:92%;--iso-m-b2:96%;--iso-m-b3:98%;
}





#top [data-iso-lanes] .iso-cue{
  display:block;box-sizing:border-box;
  margin:0;padding:5px 12px 4px;
  /* The filled accent pill, chosen in the lab against a white fill, a black
     fill and the outline ghost it replaces - four candidates side by side on
     the same plates. The plaque rides the shot's lower edge half and half,
     so it needs its own ground on both of the grounds it straddles. */
  border:1px solid #FF6238;border-radius:999px;
  background:#FF6238;color:#060607;
  font:600 9px/1.15 Inter,system-ui,sans-serif;letter-spacing:.04em;
  text-decoration:none;text-transform:none;white-space:nowrap;
  /* No shadow. It had one to lift a filled pill off a busy screenshot, and
     both halves of that reason are gone: the chip is an outline now and it
     sits off the picture. On a ring and 10px glyphs a blurred dark halo reads
     as smudge rather than as depth. */
  cursor:pointer;
}
/* Shown with the lift, and on the plate that is up: on a lone plate that is
   the hovered one, in a stack it is whichever .is-on names - so the plaque
   moves from screen to screen as the pointer walks the stack.

   Fully opaque, and that has travelled the whole road: "80% transparent" was
   asked for once, .2 was invisible in practice, .75 was the compromise - and
   with the plaque now riding the shot's lower edge the call came back as
   "nicht transparent". A label half over a busy dashboard needs its full ink. */
#top [data-iso-lanes].is-lifted .iso-plate:not(.is-zoom) .iso-cue-host,
#top [data-iso-lanes] .iso-fly.is-on .iso-plate:not(.is-zoom) .iso-cue-host{opacity:1;transition-delay:.06s}
/* Never on the decoration behind, on a picture already up, or while a stage is
   settling back down - it would be naming a gesture that is not on offer. */
/* Never on the decoration behind, never on a picture that is already up, and
   not during the half second it takes one to come back down. `.is-landing` and
   not `.is-settling`: settling is held until the pointer leaves the stage,
   which can be minutes, and while it was named here the cue never returned
   after a zoom-out at all - the pointer was still on the plate, so the state
   that was meant to cover a 560ms motion covered the whole visit. */
#top [data-iso-lanes] .iso-deco .iso-cue-host,
#top [data-iso-lanes].is-landing .iso-cue-host,
#top [data-iso-lanes].has-zoom .iso-cue-host{display:none}
@media (hover:none){
  #top [data-iso-lanes] .iso-cue-host{display:none}
}
@media (prefers-reduced-motion:reduce){
  #top [data-iso-lanes] .iso-cue-host{transition:none}
}

/* Click, and the plate flattens and fills the band. :not(.is-zoom) on the peek
   above for a reason worth keeping: a plate that has been clicked up is still
   under the pointer that clicked it, and the peek names more classes than this
   does - without it the peek won and the zoom went nowhere. */
/* Two curves, one per direction, and the difference between them was the last
   of the twitches - measured, at last, in the one browser that renders it: the
   person's own, via the flight recorder. Largest frame step 31.6px in 7ms at
   t=385ms, state [is-landing is-settling], every property mid-transition. No
   discontinuity of position anywhere - which is why no amount of auditing for
   hard cuts could find it - but a discontinuity of VELOCITY: the open curve,
   cubic-bezier(.16,1,.3,1), has an initial slope of 6.25, so the moment the
   descent began the plate went from standing still to six pixels a millisecond
   in a single frame. Three quarters of the shrink in the first seventy-five
   milliseconds reads as a snap however smooth the maths is.

   That curve is right for opening - a click wants an immediate answer - and
   wrong for putting down, which should accelerate from rest and land soft. So
   the base carries the symmetric curve and the .is-zoom rule keeps the eager
   one: the transition that runs is read from the style being entered, so the
   way up uses .is-zoom's and the way down uses this.

   The symmetric curve is the sine-like (.37,0,.63,1), and it is the second
   curve to hold this seat. The first, (.45,.05,.22,1), was continuous - the
   flight recorder's largest jump matched its theoretical peak to within 3% -
   but its peak slope is 2.7, and at full zoom that is three pixels a
   millisecond mid-descent, which read as a residual flick. This one peaks at
   about 1.6: the same half second, spent more evenly. Chosen over stretching
   the duration, which would have made every exit longer to soften only the
   largest ones. The whole descent family carries it - mask stops, plaque
   faces, the recede filter, the recentre - so everything still lands
   together, which is the lesson every earlier twitch taught. */
#top [data-iso-lanes] .iso-plate{
  transition:transform .4s cubic-bezier(.37,0,.63,1),
             scale .4s cubic-bezier(.37,0,.63,1),
             translate .4s cubic-bezier(.37,0,.63,1),
             opacity .4s ease;
}
/* The walk is quick, the way down is not. One property carries both: while the
   plate is up, translate is the pointer following the hand and has to be short
   or it trails behind; released, the same property is carrying the plate back
   to where it was lying, alongside a scale that takes half a second. At .16s it
   arrived first and the picture twitched before it had finished shrinking. The
   transition is read off the state being entered, so putting the short one on
   .is-zoom gives each direction the timing it needs. */
#top [data-iso-lanes] .iso-plate.is-zoom{
  transition:transform .4s cubic-bezier(.16,1,.3,1),
             scale .4s cubic-bezier(.16,1,.3,1),
             translate 80ms linear,
             opacity .4s ease;
  /* 80ms and linear rather than a sixth of a second of easing: an ease-out
     restarted on every frame is a chain of overlapping curves, and that was half
     of what made the walk stutter. The other half was a layout read per pointer
     event, which the script no longer does.

     There is no will-change here, and there was. It promoted the picture to a
     layer of its own while it was up, which is the textbook thing to do for
     something moved every frame - but the hint goes away the instant the class
     does, and dropping a layer that size while it is still animating is a
     re-rasterisation you can see: a flash where the picture is, right at the
     start of the way down. The walk is smooth without it, because a running
     transform transition gets a layer anyway. */
}
#top [data-iso-lanes] .iso-fly.is-zooming{z-index:9}
/* And it keeps that place until the way down is over.
   z-index is not a property that can be transitioned, so dropping it from 9 the
   instant the class goes is a hard change to paint order on a subtree that is
   still animating in 3D - one frame of re-rastering, at exactly the moment the
   picture starts travelling home. The decoration coming back from display:none
   in the same instant is the same kind of change. Both are held on a class the
   script takes off once nothing is moving any more, where a change in paint
   order costs nothing to look at.

   This was the last of them, and it was found by diffing every computed
   property of the plate and its children between the two states and keeping the
   ones no transition covers - which is what should have been done four rounds
   ago instead of reasoning about curves. */
#top [data-iso-lanes] .iso-fly.is-landing{z-index:9}
/* The way down is two moves, not one. Walked to an edge and then closed, the
   picture had to shrink and travel back at the same time - and however carefully
   the two were matched, the further it had been walked the more it jarred as it
   arrived. They are separated instead: the walk is given back first, at full
   size, and only then does the plate set down from the middle. Its own step,
   its own curve. Only the walk moves here, so the scale and the flatten keep
   the timings they have while up.

   The duration is the script's, not a constant, and the flight recorder is why:
   largest jump 23.8px in 8ms, state [is-zoom is-centring] - which is not a
   discontinuity but the honest peak velocity of a full-corner walk, close to
   400px of pan, handed back in a fixed 300ms. A step sized for the average walk
   reads as a flick on the largest one. The script measures how far the picture
   was walked and stretches the duration to hold the PEAK SPEED roughly
   constant instead; a short walk keeps the 300ms it always had, and 300ms
   stays the fallback for a plate the script has not stamped. */
/* Doubled so it outranks .is-zoom whichever order the sheet ends up in, and
   deliberately NOT tied to .is-zoom any more: the close now drops the zoom in
   the same frame the walk starts home, so the centring timing has to keep
   matching after the class is gone or the remaining pan would be re-timed
   into the descent's .4s and flick on long walks. */
#top [data-iso-lanes] .iso-plate.is-centring.is-centring{
  transition:transform .4s cubic-bezier(.16,1,.3,1),
             scale .4s cubic-bezier(.16,1,.3,1),
             translate var(--iso-recentre-ms,.3s) cubic-bezier(.37,0,.63,1),
             opacity .4s ease;
}
#top [data-iso-lanes] .iso-plate.is-zoom{
  transform:rotateX(0deg) rotateZ(0deg);
  scale:calc(var(--iso-cq,1) * var(--iso-zoom,2.2));
  cursor:zoom-out;
}
/* The slab faces fade with everything else, and this line is why the way down
   twitched long after the motion itself was in order.

   A plate at full size hides its own three extruded faces - edge-on under no
   rotation they would draw dark bars across the picture. Going back down they
   have to come back, and with nothing said about it they came back in a single
   frame: full opacity, instantly, while the plate was still flat and still
   large. .iso-side-r sits at left:100%, which is the right edge of the picture,
   so what it looked like was something appearing out of nothing over there at
   exactly the moment the plate started travelling home.

   Everything else in the exit is on a transition and was measured to land
   together; this one property was not, and no amount of matching the others
   could have helped. Same duration and curve as the rest of the way down. */
#top [data-iso-lanes] .iso-plate>span{transition:opacity .4s cubic-bezier(.37,0,.63,1)}
#top [data-iso-lanes] .iso-plate.is-zoom>span{opacity:0}
/* The same for the picture's own recede filter, which a plate behind the front
   one carries and drops while it is up. Untransitioned it snaps back on the way
   down for the same reason. */
#top [data-iso-lanes] .iso-plate>img{transition:filter .4s cubic-bezier(.37,0,.63,1)}
#top [data-iso-lanes] .iso-plate.is-zoom>img{filter:none}
/* Scenery does not answer a hover: with one plate up, the ones under it stop
   taking the pointer, or a stray hover would swap the picture out from under
   the one being read. */
#top [data-iso-lanes].iso-stage-2 .iso-plate.is-zoom{--pan-y:max(0px, calc((var(--iso-h) * var(--iso-cq,1) * var(--iso-zoom,2.2) - var(--iso-frame,100cqw) * .86) / 2))}
#top [data-iso-lanes].iso-stage-3 .iso-plate.is-zoom{--pan-y:max(0px, calc((var(--iso-h) * var(--iso-cq,1) * var(--iso-zoom,2.2) - var(--iso-frame,100cqw) * 1.15) / 2))}
#top [data-iso-lanes].has-zoom .iso-fly:not(.is-zooming) .iso-plate{opacity:.16;pointer-events:none}

/* Coming out of a zoom, the plate goes down in one motion.

   Left to itself it does not. A plate shrinking back to its resting size moves
   out from under the pointer, and if the picture was walked to an edge first,
   the pointer ends up beside where the plate lands. Hover then falls away
   part-way through the exit and takes the lone-plate peek and lift with it -
   and the lift rides the fly's own switch duration, longer than the plate's
   half second, so it was still arriving after the plate had settled. That is
   the twitch, and it only ever followed a walk.

   So for the length of the exit the answer is fixed: no peek, no lift, whatever
   the pointer is doing, and the fly on the plate's clock so the lift comes off
   with the shrink rather than a fifth of a second behind it. Half a second
   later the class goes and the true state applies - if the pointer is on the
   plate the peek comes in then, on its own half second, as a hover would.

   What this does not do any more is take the pointer away. An earlier version
   did, to decide the question at the source, and released it when the pointer
   left the band - which meant that after one zoom-out the plate answered
   nothing at all: no second zoom, no magnifier cursor, no hover, until you had
   moved off the section entirely. The twitch is worth half a second of fixed
   state; it is not worth the plate going dead.

   The doubled and tripled class names are specificity, not emphasis. The peek
   is written `:not(.iso-stage-2):not(.iso-stage-3) .iso-plate:hover:not(.is-zoom)`
   and the lone-plate lift `:has(.iso-plate:hover) .iso-fly`, both at six, so a
   rule meaning to clear them has to reach six and come later. */
#top [data-iso-lanes].is-settling.is-settling .iso-fly{--fy:0px;transition-duration:.5s,.5s,.5s}
#top [data-iso-lanes].is-settling.is-settling.is-settling:not(.iso-stage-2):not(.iso-stage-3) .iso-fly{--fy:0px}
/* :not(.is-zoom), and it is load-bearing. This rule is written at six to clear
   the peek, which puts it above the zoom's own scale at three - so a plate
   clicked up again while its stage was still settling took the class, flattened
   and centred, and then stayed the size it already was. The script also clears
   the settling state when a zoom opens; this is the half that cannot be got
   wrong by a missed call. */
#top [data-iso-lanes].is-settling.is-settling:not(.iso-stage-2):not(.iso-stage-3) .iso-plate:not(.is-zoom){
  scale:calc(var(--iso-cq,1) * var(--iso-depth,1));
}

/* A plate at full size goes to the middle of the band, wherever it was lying,
   and the pointer walks it. Three offsets come off for the centring - the stack
   offset the plate carries, and the lift its fly is holding - subtracted here
   rather than zeroed at each source, which would mean outbidding the stack
   rules that write them.

   The reach is exactly the part of the picture the frame is not showing, so at
   Explore 1 the pointer arrives at every edge and no further. The stage is the
   container, so 100cqw is the frame's own width and the reach re-derives itself
   when the column, the plate size or the zoom changes; a fixed pixel reach is
   right at one zoom only. Clamped at 0 so a plate smaller than its frame does
   not pan backwards. The vertical reach comes from the horizontal one through
   the plate's own 3:2 rather than from 100cqh: an inline-size container has no
   height to report and cqh would silently fall back to the viewport. */
#top [data-iso-lanes] .iso-plate.is-zoom{
  --pan-x:max(0px, calc((var(--iso-w) * var(--iso-cq,1) * var(--iso-zoom,2.2) - var(--iso-frame,100cqw)) / 2));
  /* The vertical reach is the real vertical overhang, not a fraction of the
     horizontal one. The 0.667 it used to be overshot it - the plate is 3:2 but
     the band is not, so at full vertical pan the picture's edge came a few
     pixels inside the window and a bare strip of page showed along it. The
     band's height is its aspect ratio times its width, which inline-size
     containment can state as cqw; the three stage classes each carry theirs. */
  --pan-y:max(0px, calc((var(--iso-h) * var(--iso-cq,1) * var(--iso-zoom,2.2) - var(--iso-frame,100cqw) * .7) / 2));
  translate:calc(var(--mx,0) * var(--pan-x) * var(--iso-explore,1) - var(--fx,0px) - var(--iso-dx,0px))
            calc(var(--my,0) * var(--pan-y) * var(--iso-explore,1) - var(--fy,0px) - var(--iso-dy,0px));
}

/* ---- 4 · the decoration -------------------------------------------------
   Lanes and terminals, drawn inside a plate of their own so they lie in the
   plate's plane: a lane that starts at the picture's left edge only stays on
   that edge if it is turned and foreshortened by the same rotation.

   Geometry is in the reference sheet's units - a 620-wide plate at (140,70) on
   a 900x640 canvas - and --acc-u scales that canvas so 620 units land on the
   plate's real width, whatever the container query says. Nothing is authored in
   pixels, so a plate at any size carries the same drawing.

   The layer sits behind the deck, which is what lets each picture cover the
   half of its own lanes that runs underneath it: they read as coming out from
   behind the slab rather than lying on top of it. */
/* The transition list here is the fly's own, plus opacity - and the "plus" is
   the whole point. This layer is an .iso-fly, so it already carried
   `transition: opacity, filter, translate` from the rule above, and it needs
   translate: on hover the stage lifts every fly by --fy, the drawing included,
   because the lanes are meant to rise with the picture they belong to.

   An earlier edition set `transition: opacity .35s ease` here to fade the
   drawing back in after a zoom, and a shorthand does not add to a list - it
   replaces it. translate and filter fell out, so the picture glided up on
   hover over 620ms while its lanes teleported the same 22 pixels in one
   frame. Measured on the customer-intelligence hero: the deco moved from
   181 to 159 with no transition covering it while the plate took 620ms to
   travel further.

   So the properties are named individually. The durations differ on purpose:
   the fade is the zoom's, at .35s, and the lift is the switch's, at whatever
   --iso-sw-ms is set to, on the same curve as the plates. */
#top [data-iso-lanes] .iso-deco{
  z-index:-1;
  opacity:1;
  transition:opacity .35s ease,
             filter calc(var(--iso-sw-ms,620) * 1ms) ease,
             translate calc(var(--iso-sw-ms,620) * 1ms) cubic-bezier(.16,1,.3,1);
}
/* The script hides this outright where a stage has no room beside it - a phone,
   or a stage that bleeds past its section on purpose. hidden is the attribute,
   so say so here too: the site sets display on a lot of things and a UA default
   of display:none loses to any of them. */
#top [data-iso-lanes] .iso-deco[hidden]{display:none}
/* The lanes are meant to reach past the plate - across the copy column on one
   side and out towards the page edge on the other - and this layer sits outside
   the deck's mask precisely so they do not dissolve on the way. The one place
   they must not go is past the frame the rest of the page lines up on.

   The cut is a clip-path with negative insets, written on this element by the
   script from the room it measured: it reaches as far out as the section's
   content box allows on each side and stops there. Negative insets expand the
   clip rect past the element's own box, which is the whole point - the layer is
   the size of the band, and the drawing is deliberately larger.

   Not overflow on this element: that clips at the band, and the band is barely
   wider than the plate, so it took most of every lane with it.

   Not overflow on the section either, although that is where the frame is. It
   works, but it clips to the padding box, and the sections do not agree on
   their padding - the hero carries none horizontally where a feature row
   carries 36px - so the same rule cuts at two different places on one page. It
   also needs a clip-margin to spare the section's own corner marks, which are
   drawn just outside its box on purpose, and that margin then lets the lanes
   past the frame by the same amount. Measuring the room and clipping here
   settles all three: one edge, the right one, per stage. */
#top [data-iso-lanes] .iso-deco .iso-plate{opacity:var(--acc-back,.1);transition:opacity .3s ease}
#top [data-iso-lanes] .iso-deco .iso-plate.is-shown{opacity:var(--acc-rest,.5)}
/* The decoration brightens with the same state, so it cannot flicker on a
   clock of its own while the plate is settling. A stack has no is-lifted - it
   answers to is-on - so both are named. */
#top [data-iso-lanes].is-lifted .iso-deco .iso-plate.is-shown,
#top [data-iso-lanes].has-on .iso-deco .iso-plate.is-shown{opacity:var(--acc-tone,1)}
/* A plate that is up gets nothing drawn around it. Two mechanisms, one per
   job. display:none while the picture is up, because it also stops the build -
   an animation that would otherwise finish behind a picture nobody can see it
   through. And opacity:0 on the container through the landing, because display
   cannot fade: releasing it late used to pop the whole drawing back in a single
   frame, sixty milliseconds after the plate touched down - which is exactly
   where "it still twitches at the end of the flight" was coming from. The
   display flip now happens underneath the held opacity, and when the landing
   lets go the drawing comes back over a third of a second, with its build
   running inside the fade.

   Container opacity rather than the ghosts', deliberately: the hover rule that
   brightens a ghost outguns any :has(.is-zoom) selector, which is how an
   earlier opacity attempt lost. Nothing else has an opinion about the
   container. */
#top [data-iso-lanes].has-zoom .iso-deco{display:none}
#top [data-iso-lanes].has-zoom > .iso-deco,
#top [data-iso-lanes].is-landing > .iso-deco{opacity:0}

#top .iso-accent{
  --acc-u:calc(var(--iso-w) / 620);
  position:absolute;
  inset:0;
}
#top .iso-accent svg{
  position:absolute;
  left:calc(-140 * var(--acc-u));
  top:calc(-70 * var(--acc-u));
  width:calc(900 * var(--acc-u));
  height:calc(640 * var(--acc-u));
  overflow:visible;
}
/* The double frame, 36 and 66 units out. Reach pulls it in with the lanes, so
   the two never cross: at a short reach the rings sit inside a frame that has
   come in to meet them rather than beside one that stayed put. */
#top .iso-accent i{position:absolute;box-sizing:border-box;border:1px dashed}
#top .iso-accent .acc-frame{inset:calc(-36 * var(--acc-u) * var(--acc-reach,.55));border-color:rgba(255,98,56,.45)}
#top .iso-accent .acc-frame-2{inset:calc(-66 * var(--acc-u) * var(--acc-reach,.55));border-color:rgba(255,98,56,.15)}
/* The sheet's constants: 1px on a 3/6 dash, a 17-unit ring at 5% fill, a 3-unit
   core. As CSS rather than attributes, so the weight moves without redrawing. */
#top .iso-accent .acc-lane{fill:none;stroke:#FF6238;stroke-width:var(--acc-w,1);stroke-dasharray:3 6}
#top .iso-accent .acc-ring{fill:rgba(255,98,56,.05);stroke:#FF6238;stroke-opacity:.5;stroke-width:var(--acc-w,1)}
#top .iso-accent .acc-core{fill:#FF6238;fill-opacity:.85}
#top .iso-accent .acc-ring,
#top .iso-accent .acc-core{transform-box:fill-box;transform-origin:center}

/* The build. Dashes grow in along each lane and the terminals arrive behind
   them, ordered outwards. A one-shot carried by a class the script puts on and
   takes off again, not a hover state: a set that rebuilt every time the pointer
   crossed the plate it was already on read as a flicker. It plays when the set
   arrives with its plates, when the front of a stack moves to another shot, and
   when a zoom closes - which is why a lone plate builds exactly once on the way
   in. .is-lead is the arrival, holding the set at its first frame until the
   plate it belongs to has landed. */
#top .iso-deco .iso-plate.is-build .acc-lane{
  animation:acc-lane-in .52s cubic-bezier(.25,.8,.3,1) backwards;
  animation-delay:calc(var(--i,0) * 55ms);
}
#top .iso-deco .iso-plate.is-build .acc-ring,
#top .iso-deco .iso-plate.is-build .acc-core{
  animation:acc-dot-in .4s cubic-bezier(.25,.8,.3,1) backwards;
  animation-delay:calc(230ms + var(--i,0) * 55ms);
}
#top .iso-deco .iso-plate.is-build.is-lead .acc-lane{
  animation-delay:calc(var(--acc-lead,900ms) + var(--i,0) * 55ms);
}
#top .iso-deco .iso-plate.is-build.is-lead .acc-ring,
#top .iso-deco .iso-plate.is-build.is-lead .acc-core{
  animation-delay:calc(var(--acc-lead,900ms) + 230ms + var(--i,0) * 55ms);
}
/* The dashes grow out of nothing and march a little on the way in, which reads
   as the lane being traced without needing a mask to draw it: a 3/6 dash cannot
   be revealed with dashoffset, that only slides the pattern along. */
@keyframes acc-lane-in{from{stroke-dasharray:0 9;stroke-dashoffset:16;opacity:0}}
@keyframes acc-dot-in{from{scale:.35;opacity:0}}

@media (prefers-reduced-motion: reduce){
  #top [data-iso-lanes] .iso-fly,
  #top [data-iso-lanes] .iso-plate,
  #top .iso-deco .iso-plate{transition:none}
  #top .iso-deco .iso-plate.is-build .acc-lane,
  #top .iso-deco .iso-plate.is-build .acc-ring,
  #top .iso-deco .iso-plate.is-build .acc-core{animation:none}
}

/* ---- Firefox without :has() ----------------------------------------------
   Found on Firefox 109, where the zoom half-worked: the picture flattened and
   grew, but the decoration's dot lanes stayed drawn IN FRONT of it and the
   walk never moved. Both mechanics - and the mask window, the ghost dimming,
   the cue's zoom-hide - hung off :has(), which that Firefox does not parse.
   Worse than inert: an unparsed selector voids its whole comma list, so even
   the class-based selectors sharing a rule with a :has() died with it.

   The script already owns every state :has() was reading, so it now mirrors
   them as classes where the state lives - .has-on / .has-zoom on the stage,
   .is-zooming on the fly - and the selectors above read those instead. Chrome
   renders identically; a browser without :has() gets the whole mechanic.

   The walk's other Firefox failure was cqw: container query units arrived in
   Firefox 110, and a calc() carrying an unknown unit voids the translate that
   consumes it - zoom scale worked, follow did not. The script measures each
   stage into --iso-frame (px) and the pan reaches read it, with 100cqw kept
   as the fallback for a stage the script has not measured yet.

   Two layout rules from iso-plate.css sit in the same :has() hole; their
   class twins live here rather than there because this file ships from the
   footer on this session's cadence, while iso-plate.css rides the bundle. */
#top .mcp-media-col.has-iso{width:100%;max-width:none}
#top section.has-iso{padding-top:64px;padding-bottom:64px}

/* ---- 8px more air under the green status dots ----------------------------
   The metric-grid dots - the glowing green disc that opens each box on the
   home page and every product page - ship from the head bundle:
   `main#top .metric-grid [class*="text-label-accent-size-11"]` gets font-size
   0, a 9px line, and the ::before disc; the 8px under the line comes from the
   label class's own margin-bottom. Asked for, third revision: 4px above and 16px below, everywhere. The
   bundle's source lives in the other session's tree, so the override rides
   this file, which loads from the footer after the bundle and outranks the
   (0,1,0) margin on weight alone. Semantically this is not an iso rule; it is
   here because this file is the one footer-loaded, versioned stylesheet this
   session owns. The matching bento-dot spacing (18px) is set in the three
   product pages' own head blocks. */
/* Reworked again, structurally this time: the dot moves off its own line and
   sits INLINE before the heading text, vertically centred on it (screenshot-
   approved). The old dot line - the label span the bundle turns into a disc -
   is hidden outright, and the disc is redrawn on the heading's own ::before,
   which is the same trick the bento pages use. The attribute selector covers
   Webflow's numbered variants of the heading class. */
main#top .metric-grid [class*="text-label-accent-size-11"]{display:none}
main#top .metric-grid [class*="text-label-primary-size-15"]::before{
  content:"";display:inline-block;width:9px;height:9px;border-radius:50%;
  background:#4FE08F;box-shadow:0 0 14px 3px rgba(79,224,143,.9);
  margin-right:12px;vertical-align:1px;
}

/* The home page: NOT its bento (Measure everything / Know your profit / Move
   the budget - dotted for one round, then asked off again), but the four
   related cards under it: Data-driven attribution, Marketing mix modeling,
   Experimentation, Most advanced tracking. Those cards sit inside a
   .metric-grid, so their small accent-size-11 dot-lines were swept up by the
   display:none above and their discs vanished with the inline rework; the
   disc comes back on the card title itself, inline before the words. The
   home page's head field is 16KB of generated code this session does not
   rewrite, so the rule rides here, scoped to that page. */
html[data-wf-page="6a82e9acbdb739d167923535"] main#top .metric-grid .related-card-title::before{
  content:"";display:inline-block;width:9px;height:9px;border-radius:50%;
  background:#4FE08F;box-shadow:0 0 14px 3px rgba(79,224,143,.9);
  margin-right:12px;vertical-align:2px;
}

/* ---- /connect/api + /connect/mcp: the viz hero on the flat card ----------
   The same treatment /measure/conversion-signals carries in its own footer
   field (that block and the /measure/multi-touch-attribution master carry
   the full annotations): the hero illustration rides a leaning panel sized
   like the screenshot-hero cards - 500:294, locked to 420px on desktop,
   centred beside the copy plus 30px, the gradient ground with the shared
   hairline, veils right 48-84% and bottom 42-94%, frame clip, slide-in from
   the right, admVizHeroGuard hiding it before first paint. It lives HERE
   rather than in the pages' own footer fields because both are too full for
   the block: the API field is a few hundred characters under its
   10,000-character cap with the MCP video and related-cards blocks already
   in it - the write came back 406 - and the MCP page's field carries the
   same two blocks at around 8,100 characters, which the 2,600-character
   block would push past the cap. This file is the one versioned,
   footer-loaded sheet this session owns, so both ride it page-scoped, same
   as the home page's related-card dots. */
html[data-wf-page="6a8c4b7c38c0b4bd58374314"] main#top#top section.shared-section-padding-80px-0-88px .mcp-hero-media,
html[data-wf-page="6a832ca92507e5ebb03ec2ca"] main#top#top section.shared-section-padding-80px-0-88px .mcp-hero-media{
  position:relative !important;
  height:auto !important;
  width:100% !important;
  aspect-ratio:500/294 !important;
  box-sizing:border-box !important;
  display:flex !important;align-items:flex-start !important;justify-content:flex-start !important;
  background:transparent !important;
  border:0 !important;
  transform:skewX(-5.97deg) translateX(8px);
  transform-origin:0 100% !important;
  -webkit-mask-image:linear-gradient(to right,#000 48%,transparent 84%),linear-gradient(to bottom,#000 42%,transparent 94%) !important;
  mask-image:linear-gradient(to right,#000 48%,transparent 84%),linear-gradient(to bottom,#000 42%,transparent 94%) !important;
  -webkit-mask-composite:source-in !important;
  mask-composite:intersect !important;
  animation:adm-viz-hero-in .8s cubic-bezier(.2,.7,.2,1) .15s both;
}
@keyframes adm-viz-hero-in{from{opacity:0;transform:skewX(-5.97deg) translateX(72px)}to{opacity:1;transform:skewX(-5.97deg) translateX(8px)}}
@media (min-width:1025px){
  html[data-wf-page="6a8c4b7c38c0b4bd58374314"] main#top,
  html[data-wf-page="6a832ca92507e5ebb03ec2ca"] main#top{overflow-x:clip}
  html[data-wf-page="6a8c4b7c38c0b4bd58374314"] main#top#top section.shared-section-padding-80px-0-88px .mcp-hero-media,
  html[data-wf-page="6a832ca92507e5ebb03ec2ca"] main#top#top section.shared-section-padding-80px-0-88px .mcp-hero-media{height:420px !important;width:auto !important;max-width:none !important;align-self:center !important;top:30px !important}
}
html[data-wf-page="6a8c4b7c38c0b4bd58374314"] main#top#top section.shared-section-padding-80px-0-88px .mcp-hero-media img,
html[data-wf-page="6a832ca92507e5ebb03ec2ca"] main#top#top section.shared-section-padding-80px-0-88px .mcp-hero-media img{
  position:static !important;
  width:68% !important;height:auto !important;max-height:72% !important;
  object-fit:contain !important;margin:6% 0 0 6% !important;
}
@media (prefers-reduced-motion:reduce){
  html[data-wf-page="6a8c4b7c38c0b4bd58374314"] main#top#top section.shared-section-padding-80px-0-88px .mcp-hero-media,
  html[data-wf-page="6a832ca92507e5ebb03ec2ca"] main#top#top section.shared-section-padding-80px-0-88px .mcp-hero-media{animation:none;opacity:1 !important;transform:skewX(-5.97deg) translateX(8px)}
}
@media (max-width:767px){
  html[data-wf-page="6a8c4b7c38c0b4bd58374314"] main#top#top section.shared-section-padding-80px-0-88px,
  html[data-wf-page="6a832ca92507e5ebb03ec2ca"] main#top#top section.shared-section-padding-80px-0-88px{padding-bottom:44px !important}
}

/* Nine more pages join, named one by one: customer-intelligence,
   experimentation, conversion-signals, panels, profit-intelligence (its upper
   trio and its lower pair), creative-intelligence, budget-optimizer,
   unified-budgeting, ad-pilot. Page-scoped rather than site-wide on purpose -
   each page also carries grids that were NOT asked for and share the same
   classes: the five-up capability band (grid-5), ad-pilot's orange accent
   trio (a green disc on the accent ground), profit-intelligence's four-card
   cost grid and panels' use-case wall (both grid-2), and conversion-signals'
   problem bento, which is the same class combo as its solution trio and only
   differs by the section it sits in. The :not() chain and the one section
   scope carve exactly the asked-for blocks out of that. */
html[data-wf-page="6a8cd915564d9a323f6b96d8"] main#top .mcp-benefit-grid-grid:not(.mcp-benefit-grid-5):not(.mcp-benefit-grid-2):not(.mcp-benefit-grid-accent) .mcp-benefit-label-size-19::before,
html[data-wf-page="6a8cd2ec19f1dd839cf0a3ab"] main#top .mcp-benefit-grid-grid:not(.mcp-benefit-grid-5):not(.mcp-benefit-grid-2):not(.mcp-benefit-grid-accent) .mcp-benefit-label-size-19::before,
html[data-wf-page="6a8cd2f4564d9a323f67ca4b"] main#top .mcp-benefit-grid-grid:not(.mcp-benefit-grid-5):not(.mcp-benefit-grid-2):not(.mcp-benefit-grid-accent) .mcp-benefit-label-size-19::before,
html[data-wf-page="6a8cd914564d9a323f6b953e"] main#top .mcp-benefit-grid-grid:not(.mcp-benefit-grid-5):not(.mcp-benefit-grid-2):not(.mcp-benefit-grid-accent) .mcp-benefit-label-size-19::before,
html[data-wf-page="6a8cd91c564d9a323f6b9c9a"] main#top .mcp-benefit-grid-grid:not(.mcp-benefit-grid-5):not(.mcp-benefit-grid-2):not(.mcp-benefit-grid-accent) .mcp-benefit-label-size-19::before,
html[data-wf-page="6a8cdeb727244368070bdada"] main#top .mcp-benefit-grid-grid:not(.mcp-benefit-grid-5):not(.mcp-benefit-grid-2):not(.mcp-benefit-grid-accent) .mcp-benefit-label-size-19::before,
html[data-wf-page="6a8cdeb8564d9a323f6e666d"] main#top .mcp-benefit-grid-grid:not(.mcp-benefit-grid-5):not(.mcp-benefit-grid-2):not(.mcp-benefit-grid-accent) .mcp-benefit-label-size-19::before,
html[data-wf-page="6a8cdeb82d0490f5afc47557"] main#top .mcp-benefit-grid-grid:not(.mcp-benefit-grid-5):not(.mcp-benefit-grid-2):not(.mcp-benefit-grid-accent) .mcp-benefit-label-size-19::before,
html[data-wf-page="6a8cd2f39002dc5efb90998e"] main#top section.shared-section-padding-0-0-96px .mcp-benefit-grid-grid .mcp-benefit-label-size-19::before,
html[data-wf-page="6a8cd914564d9a323f6b953e"] main#top section.shared-section-padding-96-0-0-0px .mcp-benefit-grid-2 .mcp-benefit-label-size-19::before{
  content:"";display:inline-block;width:9px;height:9px;border-radius:50%;
  background:#4FE08F;box-shadow:0 0 14px 3px rgba(79,224,143,.9);
  margin-right:12px;vertical-align:2px;
}

/* ---- The green dots blink, in a staggered wave ---------------------------
   Asked for on every dot, site-wide, from a supplied template. Adapted rather
   than pasted: the dots here are ::before pseudo-elements (the metric-grid
   ones from the head bundle, the bento ones from three pages' own head code),
   so the template's per-element JS delay cannot reach them - an inline style
   never addresses a pseudo. The stagger rides :nth-child on the tile
   containers instead, which is the template's own CSS fallback: every dot
   sits in its own tile, so the tile's position is the dot's position. Eight
   steps of 100ms, then the wave repeats across wider grids; the period is
   2.9s, so even the eighth dot is well inside one cycle.

   The animation lands on the same two selectors the spacing override uses,
   wherever the page's own code has given the ::before a content - a page
   without the dots has no box to animate. Reduced motion turns it off. */
@keyframes adm-launch-blink{
  0%,100%{opacity:1;box-shadow:0 0 14px 3px rgba(79,224,143,.9)}
  50%{opacity:.35;box-shadow:0 0 6px 1px rgba(79,224,143,.4)}
}
main#top .metric-grid [class*="text-label-primary-size-15"]::before,
main#top .mcp-benefit-grid-grid .mcp-benefit-label-size-19::before,
main#top .mcp-benefit-grid-2 .mcp-benefit-label-size-19::before{
  animation:adm-launch-blink 2.9s ease-in-out infinite;
  animation-delay:.1s;
}
main#top .mcp-benefit-grid-2 > :nth-child(2) .mcp-benefit-label-size-19::before{animation-delay:.2s}
main#top .metric-grid .related-card-title::before{animation:adm-launch-blink 2.9s ease-in-out infinite;animation-delay:.1s}
main#top .metric-grid > :nth-child(2) .related-card-title::before{animation-delay:.2s}
main#top .metric-grid > :nth-child(3) .related-card-title::before{animation-delay:.3s}
main#top .metric-grid > :nth-child(4) .related-card-title::before{animation-delay:.4s}
main#top .metric-grid > :nth-child(2) [class*="text-label-primary-size-15"]::before,
main#top .mcp-benefit-grid-grid > :nth-child(2) .mcp-benefit-label-size-19::before{animation-delay:.2s}
main#top .metric-grid > :nth-child(3) [class*="text-label-primary-size-15"]::before,
main#top .mcp-benefit-grid-grid > :nth-child(3) .mcp-benefit-label-size-19::before{animation-delay:.3s}
main#top .metric-grid > :nth-child(4) [class*="text-label-primary-size-15"]::before,
main#top .mcp-benefit-grid-grid > :nth-child(4) .mcp-benefit-label-size-19::before{animation-delay:.4s}
main#top .metric-grid > :nth-child(5) [class*="text-label-primary-size-15"]::before,
main#top .mcp-benefit-grid-grid > :nth-child(5) .mcp-benefit-label-size-19::before{animation-delay:.5s}
main#top .metric-grid > :nth-child(6) [class*="text-label-primary-size-15"]::before,
main#top .mcp-benefit-grid-grid > :nth-child(6) .mcp-benefit-label-size-19::before{animation-delay:.6s}
main#top .metric-grid > :nth-child(7) [class*="text-label-primary-size-15"]::before,
main#top .mcp-benefit-grid-grid > :nth-child(7) .mcp-benefit-label-size-19::before{animation-delay:.7s}
main#top .metric-grid > :nth-child(8) [class*="text-label-primary-size-15"]::before,
main#top .mcp-benefit-grid-grid > :nth-child(8) .mcp-benefit-label-size-19::before{animation-delay:.8s}
@media (prefers-reduced-motion:reduce){
  main#top .metric-grid [class*="text-label-primary-size-15"]::before,
  main#top .mcp-benefit-grid-grid .mcp-benefit-label-size-19::before,
  main#top .mcp-benefit-grid-2 .mcp-benefit-label-size-19::before,
  main#top .metric-grid .related-card-title::before{animation:none}
}

/* ---- Viz card, glass edition: transparent, no border ---------------------
   Asked for while iterating on the illustration heroes ("the card should be
   transparent and no border"). The api + mcp block above already lost its
   ground and hairline in place; the seven pages that carry the same card in
   their OWN footer fields are overridden from here instead of rewriting seven
   near-full fields. Their blocks parse after this sheet and also say
   !important, so this wins on specificity alone: html[data-wf-page] adds a
   type and an attribute on top of the same two ids. Ad Pilot's card sits on
   .mcp-media-col, the other six on .mcp-hero-media. Veils, lean, sizing and
   entrance all stay - only ground and rim go. */
html[data-wf-page="6a8c9c7c7f0f4916eb3a0755"] main#top#top section.shared-section-padding-80px-0-88px .mcp-hero-media,
html[data-wf-page="6a8cce9ae98d44bd7d20b357"] main#top#top section.shared-section-padding-80px-0-88px .mcp-hero-media,
html[data-wf-page="6a8c9c7b3323901dcc33778a"] main#top#top section.shared-section-padding-80px-0-88px .mcp-hero-media,
html[data-wf-page="6a8cd2f4564d9a323f67ca4b"] main#top#top section.shared-section-padding-80px-0-88px .mcp-hero-media,
html[data-wf-page="6a8cd91d2724436807099fd9"] main#top#top section.shared-section-padding-80px-0-88px .mcp-hero-media,
html[data-wf-page="6a8cd2f39002dc5efb90998e"] main#top#top section.shared-section-padding-80px-0-88px .mcp-hero-media,
html[data-wf-page="6a8cdeb82d0490f5afc47557"] main#top#top section.shared-section-padding-80px-0-88px .mcp-media-col{
  background:transparent !important;
  border:0 !important;
}

/* ---- Related cards take the small feature type ---------------------------
   The four-up feature/related cards - "MCP & Agents / Data Exports / Data API
   / Conversion Signals" on /connect/open-data-layer, and the same component
   on /connect/mcp, /analyze/creative-intelligence, the home page and the rest
   - shipped their titles at 25px over 16px copy, a size up from the bento
   features beside them. Asked to match the smaller feature style, named by
   reference: "Winners you can trust" on /analyze/creative-intelligence, which
   is .mcp-benefit-label-size-19 over .content-copy-size-13-5. Site-wide on
   request ("fix it generally"), so it rides this sheet unscoped. The values
   are that reference's computed ones: 19px/24.7 at Manrope 700 with the same
   -.015em tracking, 13.5px/20.925 Inter copy in the reference's muted grey
   (the cards' copy was a step lighter). The home page's inline green disc
   rides .related-card-title's ::before and follows the new size untouched. */
main#top .related-card-title{font-size:19px;line-height:24.7px;letter-spacing:-.015em}
main#top .related-card-copy{font-size:13.5px;line-height:20.925px;color:#9A9893}

/* ---- Kicker chips: the label sits optically centred ----------------------
   The hero kicker badges ("Creative Intelligence", "Admetrics MCP" and
   family) centre their LINE BOX, which is not where the eye looks. Measured
   on the live chip at 12px Inter in a 28.4px pill: cap height 8.73, descender
   2.59, and the two candidate centres are 1.3px apart in opposite directions.
   Centre the CAP BAND and a label with a descender ("Intelligence") reads
   low; centre the INK and a label without one ("Admetrics MCP") reads high -
   which is exactly the pair of reports this went through, v46 having moved a
   full pixel to the ink side. Half a pixel sits between them: no label of
   either kind is off by more than ~0.9px, under what the eye resolves at this
   size. The second rule is the 10px label variant some product pages restyle
   from their head fields at (1,2,0) with 4/4 padding - restated at (1,2,1)
   with the same half-pixel transfer. Chip heights are unchanged either way:
   the paddings still sum to what the shared sheet ships. */
main#top .badge{padding-top:5.5px;padding-bottom:6.5px}
main#top .badge-outline-label-style.badge-outline-label-style{padding-top:3.5px;padding-bottom:4.5px}

/* ---- Tablet and phone: two sections that lose the page gutter ------------
   Reported on /connect/mcp, and both patterns are shared, so both rules are
   site-wide. Below 1025px the page frame's gutter is 20px, and these two
   blocks each get it wrong in the opposite direction:

   1. A section that carries the gutter itself AND holds a container with its
      own 36px inset stacks the two - measured 57px of inset on a 375px
      screen, against 21px for every other section on the page ("Hallucination-
      proof by design."). The container's inset is a desktop measure inside a
      1288px frame; on a phone the section's gutter is the whole budget, so
      the container gives its own up.

   2. The related-cards section on /connect/mcp, /connect/api and
      /measure/tracking is driven by `#top [data-mcp-related-section]`, which
      zeroes its side padding below 1025px and bleeds -20px - so headings and
      card copy sat ON the frame edge ("Data exports" at x=1). The gutter goes
      back on the section, which is what the same block already does on the
      pages that use the plain class (open-data-layer, creative-intelligence:
      20px, content at 21). Doubled #top AND !important: that page rule sets
      its zero with !important of its own, so weight alone was not enough -
      v47 shipped without it and the gutter stayed shut. */
@media (max-width:1024px){
  main#top section[class*="section-padding"] [class*="layout-container-padding-24px-36px"]{padding-left:0;padding-right:0}
  main#top#top [data-mcp-related-section]{padding-left:20px !important;padding-right:20px !important}
}

/* ---- The home hero's stage switcher gets air underneath ------------------
   On a phone the Connect/Measure/Analyze/Allocate control sits over the
   artwork, and the artwork's bottom edge IS the section's - 7px under the
   control, measured at 375px, before the customer band's own 32px. 16px more
   on the section, asked for on review. Desktop is untouched: the hero's
   min-height rule up there only runs from 1025px. */
@media (max-width:767px){
  html[data-wf-page="6a82e9acbdb739d167923535"] main#top .hero-grid-section-display-flex{padding-bottom:16px}
}

/* ---- The TV quote loses the browser's blockquote rule --------------------
   The quote body is a <blockquote>, and Webflow's shared sheet styles the bare
   tag: `border-left:5px solid #e2e2e2; padding:10px 20px`. The component's own
   .tv-quote-content class takes the padding back but never the border, so a
   grey 5px bar stood beside the quote on every page that got the block - the
   home page only looks right because its page field kills the border locally.
   Site-wide here, so the next page to take the component is right on arrival.
   (1,1,1) against the bare tag's (0,0,1); nothing else on the site draws a
   left edge on this element. */
main#top .tv-quote-content{border-left:0}

/* ---- The TV quote's Tales & Tails mark comes down 27% --------------------
   .tv-quote-logo is a fixed 150px wide for every customer mark in the quote,
   which is right for a horizontal wordmark (SugarGang, ESN) and wrong for a
   near-square script one: at the same width Tales & Tails renders roughly
   three times the height and dominates the panel. 109.5px is the asked-for
   27% down. Keyed to the file rather than to the class, so every other mark
   keeps the shared width and this one travels with the quote if it is placed
   on another page. */
main#top .tv-quote-logo[src*="tales-tails"]{width:109.5px}

/* ---- The TV quote's role line comes up a step ----------------------------
   "Founder, Tales & Tails" and its siblings sat at 13.5px under a 19px name -
   the smallest type in the panel, on a light ground at .58 opacity, and it
   read as a caption rather than as the attribution it is. 15px is the site's
   own body size and the asked-for step up (1-2px); the line-height keeps the
   1.3 ratio it already had. The phone step follows by the same 1.5px, so the
   pair keeps its proportion where the shared sheet drops the line to 12. */
main#top .tv-quote-role{font-size:15px;line-height:1.3}
@media screen and (max-width:479px){
  main#top .tv-quote-role{font-size:13.5px}
}
