/* ============================================================
   12 — ADVANCED
   The graphics that mean something.

   Layers 08 to 11 are atmosphere, motion and components. This one
   is different: every effect here encodes a fact about the product
   rather than decorating around it.

   A flow map shows where a signal actually goes. A gauge shows a
   percentile against its budget. A flip digit shows that a number
   CHANGED, which on a trading screen is the whole message. If an
   effect here cannot answer "what does this tell me", it does not
   belong in this file.
   ============================================================ */

@property --arc{syntax:"<number>";initial-value:0;inherits:false}
@property --dash{syntax:"<length>";initial-value:0px;inherits:false}

/* ---------- 01. FLOW MAP -------------------------------------
   source → parser → account, with dashes travelling along the
   path. This is the product's actual shape, so it is worth
   drawing rather than describing.

   The dashes move by animating stroke-dashoffset, which stays on
   the compositor. Animating the path itself would repaint.
   ------------------------------------------------------------ */
.flowmap{width:100%;height:auto;overflow:visible;display:block}
.flowmap .wire{
  fill:none;stroke:var(--line);stroke-width:1.5;stroke-linecap:round;
}
.flowmap .live{
  fill:none;stroke:url(#flowGrad);stroke-width:2;stroke-linecap:round;
  stroke-dasharray:7 11;
  animation:flowrun 1.4s linear infinite;
}
.flowmap .live.slow{animation-duration:2.6s;opacity:.55}
@keyframes flowrun{to{stroke-dashoffset:-36}}

.flowmap .node{fill:var(--deep);stroke:var(--line);stroke-width:1.5}
.flowmap .node.on{stroke:var(--blue)}
.flowmap .halo{fill:none;stroke:var(--cyan);stroke-width:1.5;opacity:0;transform-box:fill-box;transform-origin:center}
.flowmap .halo.beat{animation:nodebeat 2.2s ease-out infinite}
@keyframes nodebeat{
  0%  {opacity:.55;transform:scale(.72)}
  70% {opacity:0;   transform:scale(1.5)}
  100%{opacity:0;   transform:scale(1.5)}
}
.flowmap text{fill:var(--dim);font:500 11px var(--mono);letter-spacing:.04em}
.flowmap text.hd{fill:var(--text);font:600 12.5px var(--display);letter-spacing:-.01em}
.flowmap text.sm{fill:var(--faint);font:400 10px var(--mono)}

/* ---------- 02. GAUGE ----------------------------------------
   A percentile against its budget. The arc is a conic gradient
   masked to a ring, so there is no SVG and no JavaScript for the
   shape — only --arc, which is a registered property and therefore
   transitionable.
   ------------------------------------------------------------ */
.gauge{
  --arc:0;
  position:relative;width:112px;height:112px;flex:0 0 auto;
  border-radius:50%;
  background:
    conic-gradient(from 180deg,
      var(--cyan) 0turn,
      var(--blue) calc(var(--arc) * .32turn),
      var(--violet) calc(var(--arc) * .5turn),
      rgba(255,255,255,.06) calc(var(--arc) * .5turn),
      rgba(255,255,255,.06) .5turn,
      transparent .5turn);
  -webkit-mask:radial-gradient(farthest-side,transparent calc(100% - 9px),#000 calc(100% - 9px));
  mask:radial-gradient(farthest-side,transparent calc(100% - 9px),#000 calc(100% - 9px));
  transition:--arc 1.1s cubic-bezier(.2,.7,.3,1);
}
.gauge-wrap{position:relative;display:inline-flex;align-items:center;justify-content:center}
.gauge-val{
  position:absolute;text-align:center;line-height:1.15;
  transform:translateY(6px);          /* the arc is a half-circle */
}
.gauge-val b{display:block;font:700 22px/1 var(--display);letter-spacing:-.03em}
.gauge-val span{display:block;font:400 10px/1 var(--mono);color:var(--faint);
  letter-spacing:.14em;text-transform:uppercase;margin-top:4px}
.gauge.over{--arc:1}
.gauge.warn{filter:hue-rotate(-38deg)}
.gauge.bad{filter:hue-rotate(-72deg) saturate(1.3)}

/* ---------- 03. FLIP DIGITS ----------------------------------
   A number that CHANGED, which on a trading screen is the whole
   message. The old value slides out, the new one slides in, and
   the direction of travel carries the sign.
   ------------------------------------------------------------ */
.flip{display:inline-flex;align-items:baseline;font-variant-numeric:tabular-nums}
.flip .col{
  position:relative;display:inline-block;height:1em;overflow:hidden;vertical-align:baseline;
}
.flip .col i{display:block;font-style:normal}
.flip .col.up i   {animation:flipup .38s cubic-bezier(.2,.7,.3,1)}
.flip .col.down i {animation:flipdown .38s cubic-bezier(.2,.7,.3,1)}
@keyframes flipup  {from{transform:translateY(100%);opacity:0}to{transform:none;opacity:1}}
@keyframes flipdown{from{transform:translateY(-100%);opacity:0}to{transform:none;opacity:1}}
.flip.rose{color:var(--rose)}
.flip.mint{color:var(--mint)}

/* ---------- 04. ACTIVITY PULSE -------------------------------
   A source badge that pulses when that source delivers. Rare and
   short: a badge that pulses constantly is a badge nobody reads.
   ------------------------------------------------------------ */
.src.hot i{position:relative}
.src.hot i::after{
  content:"";position:absolute;inset:-3px;border-radius:7px;
  border:1px solid var(--cyan);
  animation:srcbeat 1.6s ease-out 3;
}
@keyframes srcbeat{
  0%  {opacity:.7;transform:scale(.8)}
  100%{opacity:0; transform:scale(1.55)}
}

/* ---------- 05. SPARKLINE ------------------------------------
   Pure CSS bars, no canvas and no library. Each bar's height is a
   custom property, so the markup carries the data and the
   stylesheet carries none of it.
   ------------------------------------------------------------ */
.spark{display:flex;align-items:flex-end;gap:2px;height:34px}
.spark i{
  flex:1;min-width:2px;border-radius:2px 2px 0 0;
  height:calc(var(--h,10) * 1%);
  background:linear-gradient(180deg,var(--cyan),rgba(168,85,247,.25));
  transform-origin:50% 100%;
  animation:sparkin .5s cubic-bezier(.2,.7,.3,1) both;
}
.spark i:nth-child(2n){animation-delay:.03s}
.spark i:nth-child(3n){animation-delay:.06s}
.spark i.hi{background:linear-gradient(180deg,var(--violet),rgba(109,59,245,.25))}
.spark i.low{background:linear-gradient(180deg,var(--rose),rgba(255,107,90,.2))}
@keyframes sparkin{from{transform:scaleY(0)}to{transform:scaleY(1)}}

/* ---------- 06. CRT ------------------------------------------
   A scanline and a faint bloom on the live console only. It reads
   as "this is a screen showing a machine", which is exactly what
   that panel is.
   ------------------------------------------------------------ */
.crt{position:relative;isolation:isolate}
.crt::after{
  content:"";position:absolute;inset:0;pointer-events:none;z-index:2;border-radius:inherit;
  background:repeating-linear-gradient(180deg,
    rgba(255,255,255,.028) 0 1px, transparent 1px 3px);
  mix-blend-mode:overlay;
}
.crt::before{
  content:"";position:absolute;left:0;right:0;height:38%;top:-38%;pointer-events:none;z-index:3;
  background:linear-gradient(180deg,transparent,rgba(255,79,216,.055),transparent);
  animation:crtsweep 7s linear infinite;
}
@keyframes crtsweep{to{top:110%}}

/* ---------- 07. ROW BLOOM ------------------------------------
   A table row that lights from where the pointer is. Rows are the
   most-scanned element in the dashboard, so the feedback goes
   there rather than on something decorative.
   ------------------------------------------------------------ */
.tbl tbody tr{position:relative}
.tbl tbody tr:hover{
  background-image:radial-gradient(240px circle at var(--mx,50%) 50%,
    rgba(168,85,247,.14), transparent 70%);
}

/* ---------- 08. ISO STACK ------------------------------------
   Three plates in isometric, for "one signal, many accounts". The
   fan is the fact.
   ------------------------------------------------------------ */
.iso{perspective:900px;display:inline-block}
.iso .plate{
  position:relative;border:1px solid var(--line);border-radius:10px;
  background:linear-gradient(150deg,rgba(255,255,255,.06),rgba(255,255,255,.02));
  transform:rotateX(52deg) rotateZ(-38deg);
  transform-style:preserve-3d;
  box-shadow:0 24px 50px -34px rgba(0,0,0,.9);
}
.iso .plate + .plate{margin-top:-58%}
.iso .plate:nth-child(1){opacity:.45}
.iso .plate:nth-child(2){opacity:.72}

/* ---------- 09. RIBBON ---------------------------------------
   One aurora band, masked so it fades at both ends. Cheaper than
   a blurred blob and reads as a horizon line.
   ------------------------------------------------------------ */
.ribbon{
  position:absolute;left:-10%;right:-10%;height:200px;pointer-events:none;z-index:0;
  background:linear-gradient(100deg,
    transparent, rgba(255,79,216,.16) 22%, rgba(168,85,247,.22) 48%,
    rgba(109,59,245,.16) 74%, transparent);
  filter:blur(34px);
  -webkit-mask:linear-gradient(90deg,transparent,#000 18%,#000 82%,transparent);
  mask:linear-gradient(90deg,transparent,#000 18%,#000 82%,transparent);
  animation:ribbondrift 22s ease-in-out infinite alternate;
}
@keyframes ribbondrift{
  from{transform:translate3d(0,0,0) rotate(-1.5deg)}
  to  {transform:translate3d(-4%,10px,0) rotate(1.5deg)}
}

/* ---------- 10. EDGE CHROMA ----------------------------------
   A one-pixel gradient on the leading edge of a panel. Almost
   subliminal, and it is what stops a grid of panels reading flat.
   ------------------------------------------------------------ */
.chroma-edge{position:relative}
.chroma-edge::before{
  content:"";position:absolute;left:0;top:12%;bottom:12%;width:2px;border-radius:2px;
  background:var(--spectrum);opacity:.85;
}

/* ---------- 11. STAT TILE, ADVANCED --------------------------- */
.stat-adv{
  display:flex;align-items:center;gap:18px;padding:18px 20px;
  border:1px solid var(--line);border-radius:var(--r);
  background:linear-gradient(160deg,rgba(255,255,255,.055),rgba(255,255,255,.025));
}
.stat-adv .body{min-width:0;flex:1}
.stat-adv .lbl{display:block;margin-bottom:6px}
.stat-adv .big{font:700 30px/1 var(--display);letter-spacing:-.04em}
.stat-adv .big small{font-size:14px;color:var(--faint);font-weight:500;margin-left:3px}
.stat-adv .sub{margin-top:6px;font-size:12px;color:var(--dim)}

/* ============================================================
   Cost control
   ============================================================ */
@media(max-width:900px){
  .crt::before{display:none}
  .ribbon{filter:blur(24px);height:140px}
  .iso .plate{transform:none;margin-top:0}
  .iso .plate + .plate{margin-top:8px}
  .gauge{width:92px;height:92px}
}

@media(prefers-reduced-motion:reduce){
  .flowmap .live,.flowmap .halo.beat,.crt::before,.ribbon,
  .spark i,.src.hot i::after,.flip .col i{animation:none !important}
  .flowmap .live{stroke-dasharray:none;opacity:.7}
  .spark i{transform:none}
  .gauge{transition:none}
}

html[data-fx-off] .flowmap .live{animation:none;stroke-dasharray:none}
html[data-fx-off] .crt::before,
html[data-fx-off] .ribbon,
html[data-fx-off] .src.hot i::after{display:none}
html[data-fx-off] .gauge{transition:none}

/* ============================================================
   TITLE SEQUENCE
   The first two seconds of the homepage.

   Four devices, staged on the same beat grid as everything else,
   and each one earning its place rather than being a flourish:

     the mark draws itself      — "this is being built, now"
     the headline masks in      — line by line, like type being set
     a constellation settles    — four sources joining one point
     the numbers roll           — the product is about milliseconds
   ============================================================ */

/* ---------- MARK DRAW ---------------------------------------- */
.markdraw path,.markdraw circle,.markdraw line{
  stroke-dasharray:var(--len,200);stroke-dashoffset:var(--len,200);
  animation:markstroke 1.15s cubic-bezier(.6,0,.2,1) forwards;
}
.markdraw .fill{
  opacity:0;animation:markfill .6s ease-out .85s forwards;
}
@keyframes markstroke{to{stroke-dashoffset:0}}
@keyframes markfill{to{opacity:1}}

/* ---------- LINE MASK ----------------------------------------
   Each line wipes in behind a moving gradient rather than fading.
   A fade says "this appeared"; a wipe says "this was set".
   ------------------------------------------------------------ */
.linemask{display:block;overflow:hidden}
.linemask > span{display:block}

/*  SCAR, and the SECOND time this exact failure has been built into this
    headline. .holo puts background-clip:text on the h1; a child that gets its
    own mask (or filter, or transform) composites into its own layer, and the
    parent's text-clipped background never reaches it. Transparent text on
    nothing: an invisible headline.

    The gradient therefore lives on the LINE, which is also where the mask
    lives. Anything that clips text and anything that composites separately
    must be the same element — that is the rule, and it is worth writing down
    because the obvious markup breaks it every time. */
.holo .linemask > span,
.holo.linemask > span{
  background:var(--spectrum);
  -webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;color:transparent;
}
.holo:has(.linemask){background:none;-webkit-text-fill-color:currentColor}

/*  The wipe starts at mask-size 0%, which means the text is INVISIBLE until
    the animation runs. On any engine without mask support the declaration is
    dropped but the animation is not, and a headline that never appears is the
    single worst failure this stylesheet can produce — it has happened once
    already on this site.

    So the whole device is behind @supports. Where masks are unavailable the
    lines are simply text, immediately, with no animation at all. */
@supports ((-webkit-mask-size: 0% 100%) or (mask-size: 0% 100%)){
  .linemask > span{
    -webkit-mask-image:linear-gradient(90deg,#000 0 0);
    mask-image:linear-gradient(90deg,#000 0 0);
    -webkit-mask-size:0% 100%;mask-size:0% 100%;
    -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
    animation:linewipe .9s cubic-bezier(.6,0,.2,1) both;
  }
  @keyframes linewipe{to{-webkit-mask-size:130% 100%;mask-size:130% 100%}}
}
/*  and if the script never runs, nothing is masked at all */
html:not(.js) .linemask > span{
  -webkit-mask-image:none !important;mask-image:none !important;animation:none !important;
}

/* ---------- CONSTELLATION ------------------------------------
   Four points converging on one. It is the product's shape at a
   glance, and it settles rather than loops — a background that
   never stops moving is a background nobody stops noticing.
   ------------------------------------------------------------ */
.constel{position:absolute;inset:0;pointer-events:none;z-index:0;overflow:hidden}
.constel svg{width:100%;height:100%}
.constel .link{
  stroke:url(#flowGrad);stroke-width:1;fill:none;opacity:0;
  stroke-dasharray:var(--len,300);stroke-dashoffset:var(--len,300);
  animation:constellink 1.6s cubic-bezier(.4,0,.2,1) forwards;
}
.constel .link:nth-child(2){animation-delay:.12s}
.constel .link:nth-child(3){animation-delay:.24s}
.constel .link:nth-child(4){animation-delay:.36s}
@keyframes constellink{
  0%  {opacity:0;stroke-dashoffset:var(--len,300)}
  25% {opacity:.55}
  100%{opacity:.22;stroke-dashoffset:0}
}
.constel .pt{
  fill:var(--cyan);opacity:0;
  animation:constelpt .5s cubic-bezier(.34,1.56,.64,1) forwards;
}
.constel .pt:nth-of-type(2){animation-delay:.14s}
.constel .pt:nth-of-type(3){animation-delay:.28s}
.constel .pt:nth-of-type(4){animation-delay:.42s}
.constel .pt.hub{r:5;fill:var(--violet);animation-delay:.6s}
@keyframes constelpt{from{opacity:0;transform:scale(0)}to{opacity:.75;transform:none}}

/* ---------- ROLL --------------------------------------------- */
.roll{display:inline-block;overflow:hidden;height:1em;vertical-align:-.12em}
.roll i{
  display:block;font-style:normal;
  animation:rollup .8s cubic-bezier(.2,.8,.2,1) both;
}
@keyframes rollup{from{transform:translateY(1.1em);opacity:0}to{transform:none;opacity:1}}

@media(prefers-reduced-motion:reduce){
  .markdraw path,.markdraw circle,.markdraw line{stroke-dashoffset:0 !important;animation:none}
  .markdraw .fill{opacity:1;animation:none}
  .linemask > span{-webkit-mask-image:none;mask-image:none;animation:none}
  .constel .link{stroke-dashoffset:0;opacity:.22;animation:none}
  .constel .pt{opacity:.75;animation:none}
  .roll i{animation:none}
}
html[data-fx-off] .constel{display:none}
html[data-fx-off] .linemask > span{-webkit-mask-image:none;mask-image:none;animation:none}
html[data-fx-off] .markdraw path,
html[data-fx-off] .markdraw circle{stroke-dashoffset:0;animation:none}
