/* ============================================================================
   CHARTVEIL — DEPTH PASS (preview only)

   An additive layer over styles.css. It adds no colour of its own and changes
   no copy: every rule here is about WHERE a thing sits in Z, and about the
   light and shadow that make that position readable.

   The model is a room, not a page:
     -400  atmosphere      fine grid + motes, moves slowest
     -160  under-glow      the light the panels are lit by
        0  the page plane  body copy, section text
      +20  slabs           panels, cards, tables — physical sheets
      +70  instruments     chips that float in front of the app window
      +90  glare           the sheen on the glass
     nav   always nearest

   Three depth cues do the work, in this order of importance:
     1. PARALLAX   things at different depths move at different rates
     2. AERIAL     things further away are dimmer, softer, lower contrast
     3. SHADOW     a slab casts onto what is behind it, and catches a rim light

   Everything is scoped to html.d3 so the preview can A/B it live, and every
   motion is transform/opacity only so it composites on the GPU.
   The three-role rule still holds: red is brand, amber is state, blue is
   liquidity. The light in here is neutral white — light is not a role.
   ========================================================================== */

html.d3{
  --d3-k:1;                 /* master intensity, driven by the preview slider */
  --d3-lift:calc(14px * var(--d3-k));
  --d3-tilt:calc(1deg * var(--d3-k));
  --d3-shadow-near:0 30px 60px -28px rgba(0,0,0,.95),0 8px 18px -12px rgba(0,0,0,.8);
  --d3-rim:inset 0 1px 0 rgba(255,255,255,.055);
}

/* ---------------------------------------------------------------------------
   1. ATMOSPHERE — three planes behind everything
   The far plane barely moves, the near one moves most. That difference IS the
   depth; the artwork itself is deliberately almost invisible.
   Sits at z-index 0, i.e. above the ambient wash on body and below main.
--------------------------------------------------------------------------- */
.d3-atmos{
  position:fixed;inset:-10%;z-index:0;pointer-events:none;
}
.d3-atmos > div{position:absolute;inset:0;will-change:transform}

.d3-far{
  background-image:
    linear-gradient(rgba(255,255,255,.028) 1px,transparent 1px),
    linear-gradient(90deg,rgba(255,255,255,.028) 1px,transparent 1px);
  background-size:150px 150px;
  transform:translate3d(0,calc(var(--d3-sy,0px) * -.014),0);
  -webkit-mask-image:radial-gradient(ellipse 80% 70% at 50% 40%,#000 10%,transparent 92%);
          mask-image:radial-gradient(ellipse 80% 70% at 50% 40%,#000 10%,transparent 92%);
  opacity:.6;
}
.d3-mid{
  background-image:radial-gradient(rgba(255,255,255,.09) 1px,transparent 1px);
  background-size:64px 64px;
  transform:translate3d(0,calc(var(--d3-sy,0px) * -.05),0);
  -webkit-mask-image:radial-gradient(ellipse 70% 60% at 50% 35%,#000 4%,transparent 78%);
          mask-image:radial-gradient(ellipse 70% 60% at 50% 35%,#000 4%,transparent 78%);
  opacity:.35;
  filter:blur(.4px);          /* aerial perspective: distance costs sharpness */
}
.d3-near{
  background-image:radial-gradient(rgba(229,53,47,.5) 1.6px,transparent 1.6px);
  background-size:280px 280px;background-position:40px 90px;
  transform:translate3d(0,calc(var(--d3-sy,0px) * -.13),0);
  -webkit-mask-image:radial-gradient(ellipse 60% 70% at 50% 30%,#000,transparent 70%);
          mask-image:radial-gradient(ellipse 60% 70% at 50% 30%,#000,transparent 70%);
  opacity:.5;
}

/* Aerial haze — the page fades into the room at the top and bottom edges of the
   viewport instead of being sliced off by them. Above content, below the nav. */
.d3-haze{
  position:fixed;inset:0;z-index:5;pointer-events:none;
  background:
    linear-gradient(to bottom,rgba(10,10,10,.8),rgba(10,10,10,0) 12%),
    linear-gradient(to top,rgba(10,10,10,.7),rgba(10,10,10,0) 10%);
}

/* ---------------------------------------------------------------------------
   2. THE NEAREST PLANE — the nav
   It was already sticky; now it reads as a pane of glass held in front of the
   page rather than a strip painted on it.
--------------------------------------------------------------------------- */
html.d3 .nav.is-stuck{
  background:rgba(10,10,10,.62);
  backdrop-filter:blur(18px) saturate(1.25);
  -webkit-backdrop-filter:blur(18px) saturate(1.25);
  box-shadow:
    0 1px 0 rgba(255,255,255,.06),
    0 18px 40px -24px rgba(0,0,0,1),
    0 30px 60px -50px rgba(229,53,47,.9);
}
html.d3 .sbar{box-shadow:0 10px 30px -22px rgba(0,0,0,.9)}

/* ---------------------------------------------------------------------------
   3. THE HERO WINDOW — the one true 3D object on the page
   .stage__wrap becomes a preserve-3d card inside a perspective box. The frame
   itself stays flat (it has overflow:hidden, which flattens 3D anyway); the
   depth comes from siblings placed in front of and behind it.
--------------------------------------------------------------------------- */
html.d3 .d3-persp{perspective:1600px;perspective-origin:50% 42%}
html.d3 .d3-persp .stage__wrap{
  transform-style:preserve-3d;
  transform:
    rotateX(var(--d3-rx,0deg)) rotateY(var(--d3-ry,0deg))
    translate3d(0,var(--d3-py,0px),0);
  transition:transform 420ms cubic-bezier(.16,1,.3,1);
  will-change:transform;
}
html.d3 .d3-persp.is-live .stage__wrap{transition:transform 90ms linear}

/* the frame gets a heavier, warmer cast now that it is a slab held above the
   page rather than a picture printed on it */
html.d3 .d3-persp .frame{
  box-shadow:
    0 0 0 1px rgba(229,53,47,.10),
    inset 0 2px 0 rgba(255,255,255,.045),
    0 60px 120px -60px rgba(229,53,47,.55),
    0 50px 90px -40px rgba(0,0,0,.95),
    0 18px 30px -20px rgba(0,0,0,.9);
}

/* the light the window is lit by, sitting well behind it */
.d3-underglow{
  position:absolute;left:50%;top:48%;width:120%;height:105%;
  transform:translate3d(-50%,-50%,-160px);
  background:radial-gradient(ellipse at 50% 50%,rgba(229,53,47,.30),rgba(229,53,47,.05) 45%,transparent 72%);
  filter:blur(60px);pointer-events:none;z-index:-1;
}
/* the shadow the window casts on the page behind it — it slides opposite the
   tilt, which is what actually sells the rotation */
.d3-cast{
  position:absolute;left:6%;right:6%;bottom:-40px;height:74px;
  transform:translate3d(var(--d3-castx,0px),0,-120px);
  background:radial-gradient(ellipse at 50% 50%,rgba(0,0,0,.9),transparent 70%);
  filter:blur(26px);pointer-events:none;z-index:-1;
}
/* the sheen on the glass: one moving highlight, pointer-driven */
.d3-glare{
  position:absolute;inset:0;border-radius:var(--r-lg);pointer-events:none;
  transform:translateZ(80px);
  background:radial-gradient(420px 320px at var(--d3-mx,50%) var(--d3-my,0%),
             rgba(255,255,255,.10),rgba(255,255,255,.035) 38%,transparent 66%);
  opacity:0;transition:opacity 260ms var(--ease);mix-blend-mode:plus-lighter;
}
html.d3 .d3-persp.is-live .d3-glare{opacity:1}

/* instrument chips — they hover IN FRONT of the window, so they parallax
   against it as it tilts. Their text is read live from the active slide, so
   they never claim anything the panel is not showing. */
.d3-chip{
  position:absolute;pointer-events:none;
  display:flex;align-items:center;gap:8px;
  padding:7px 11px;border:1px solid var(--line-strong);border-radius:var(--r-md);
  background:rgba(20,20,20,.82);backdrop-filter:blur(8px);
  font-family:var(--font-data);font-size:10px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--text-secondary);white-space:nowrap;
  box-shadow:0 18px 34px -18px rgba(0,0,0,1),var(--d3-rim);
  opacity:0;transition:opacity 380ms var(--ease);
}
.d3-chip b{color:var(--text-primary);font-weight:600;letter-spacing:.08em}
.d3-chip i{width:5px;height:5px;border-radius:50%;background:var(--liq-4);
           box-shadow:0 0 8px var(--liq-4);flex:none;font-style:normal}
.d3-chip--a{left:-26px;top:15%;transform:translateZ(84px)}
.d3-chip--b{right:-22px;bottom:20%;transform:translateZ(64px)}
.d3-chip--b i{background:var(--select);box-shadow:0 0 8px var(--select)}
html.d3 .d3-persp .d3-chip{opacity:1}
@media (max-width:1080px){ .d3-chip{display:none} }

/* the hero's own grid gets pushed back and drifts with the scroll, so the
   headline sits visibly in front of it.
   The hero vars are separate from the page-wide --d3-sy because they are
   clamped to the hero's own height: multiplying full page scroll would push
   the headline a thousand pixels off screen by the footer. */
html.d3 .hero__grid{
  transform:translate3d(0,calc(var(--d3-hy,0px) * .16),0) scale(1.06);
  opacity:.8;
}
/* headline copy rises slower than the window beside it — two planes */
html.d3 .hero__copy{transform:translate3d(0,calc(var(--d3-hy,0px) * -.10),0)}

/* ---------------------------------------------------------------------------
   4. SLABS — every panel becomes a sheet with a lit top edge and a cast below
--------------------------------------------------------------------------- */
html.d3 .frame,
html.d3 .tablewrap,
html.d3 .plan,
html.d3 .modal__card{
  box-shadow:var(--d3-shadow-near),var(--d3-rim);
}

/* the marquee is the one thing BELOW the page plane — a groove. Having one
   recessed element gives every raised one something to be raised against;
   without it "raised" is just a shadow everyone shares. */
html.d3 .trust{
  box-shadow:
    inset 0 14px 22px -16px rgba(0,0,0,1),
    inset 0 -14px 22px -16px rgba(0,0,0,1);
  background:linear-gradient(rgba(0,0,0,.35),rgba(0,0,0,0) 30%,rgba(0,0,0,.35)),var(--surface-panel);
}

/* ---------------------------------------------------------------------------
   5. TILE PLANES — the depth-of-field trick
   Hovering one tile lifts it and pushes every sibling away: dimmer, smaller,
   a breath of blur. This is the strongest 3D cue available on a flat screen,
   because it is the only one the eye cannot read as "a drawing of a shadow".
--------------------------------------------------------------------------- */
html.d3 .d3-plane{perspective:1200px;position:relative}
html.d3 .d3-tile{
  transition:transform 320ms cubic-bezier(.16,1,.3,1),
             filter 320ms var(--ease),
             box-shadow 320ms var(--ease);
  transform-style:preserve-3d;
}
/* siblings recede while the group is being pointed at */
html.d3 .d3-plane:hover > .d3-tile{
  filter:brightness(.72) saturate(.85) blur(.6px);
  transform:scale(.982) translateZ(-30px);
}
/* ...and the pointed-at one comes forward, tilting toward the cursor */
html.d3 .d3-plane > .d3-tile:hover{
  filter:none;
  z-index:3;
  transform:
    translate3d(0,calc(var(--d3-lift) * -1),60px)
    rotateX(calc(var(--d3-ty,0) * var(--d3-tilt)))
    rotateY(calc(var(--d3-tx,0) * var(--d3-tilt)));
  box-shadow:
    0 40px 70px -30px rgba(0,0,0,1),
    0 12px 24px -14px rgba(0,0,0,.9),
    0 0 0 1px var(--line-strong),
    var(--d3-rim);
}
/* a shared light source across the group, so the tiles read as one surface
   catching one lamp rather than as separate cards with separate glows */
html.d3 .d3-plane::after{
  content:'';position:absolute;inset:0;pointer-events:none;z-index:4;
  background:radial-gradient(460px 340px at var(--d3-mx,50%) var(--d3-my,50%),
             rgba(255,255,255,.07),transparent 62%);
  opacity:0;transition:opacity 300ms var(--ease);mix-blend-mode:plus-lighter;
}
html.d3 .d3-plane:hover::after{opacity:1}

/* the pricing plane starts already staged in depth: the hero plan is simply
   nearer than the others, before anyone touches it */
html.d3 .plans .plan--hero{
  transform:translateZ(50px) scale(1.015);
  box-shadow:
    0 0 0 1px rgba(229,53,47,.22),
    0 50px 90px -40px rgba(229,53,47,.55),
    0 40px 70px -34px rgba(0,0,0,1),
    var(--d3-rim);
}
html.d3 .plans .plan:not(.plan--hero){filter:brightness(.9)}
html.d3 .plans .plan:not(.plan--hero):hover{filter:none}

/* ---------------------------------------------------------------------------
   6. THE DESK WINDOW — lays itself flat as you scroll to it
   --d3-p runs 0 to 1 across the approach. The panel starts pitched back like a
   card held at an angle and settles level when it is centred in the viewport.
--------------------------------------------------------------------------- */
html.d3 .d3-lay{perspective:1800px;perspective-origin:50% 30%}
html.d3 .d3-lay > .frame{
  transform:rotateX(calc((1 - var(--d3-p,1)) * 9deg * var(--d3-k)))
            scale(calc(.965 + .035 * var(--d3-p,1)));
  transform-origin:50% 100%;
  will-change:transform;
}

/* the three desk cells sit at slightly different depths, like panes in a rack */
html.d3 .desk__grid{perspective:1400px}
html.d3 .desk__cell{transition:transform 320ms cubic-bezier(.16,1,.3,1),filter 320ms var(--ease)}
html.d3 .desk__grid:hover .desk__cell{filter:brightness(.7) blur(.7px);transform:translateZ(-24px)}
html.d3 .desk__grid .desk__cell:hover{
  filter:none;transform:translateZ(48px);z-index:2;
  box-shadow:0 40px 70px -28px rgba(0,0,0,1);
}

/* ---------------------------------------------------------------------------
   7. COUNTER-PARALLAX INSIDE SECTIONS
   Heading blocks travel a little slower than the body they head. It is a few
   pixels of difference and nobody consciously sees it, but it is the reason
   the page stops feeling like one printed sheet.
--------------------------------------------------------------------------- */
html.d3 [data-d3-drift]{
  transform:translate3d(0,var(--d3-drift,0px),0);
  will-change:transform;
}

/* ---------------------------------------------------------------------------
   8. ENTRANCE FROM DEPTH
   Content arrives from further away rather than from further down. Kept short
   and shallow — the site's rule is that content is simply present, so nothing
   here may leave text hidden for longer than a blink.
--------------------------------------------------------------------------- */
html.d3 main{perspective:1400px;perspective-origin:50% 50%}
html.d3 .reveal{
  transition:opacity 560ms var(--ease),transform 680ms cubic-bezier(.16,1,.3,1),filter 560ms var(--ease);
  transition-delay:var(--d3-delay,0ms);
}
/* THE ENTRANCE IS WRITTEN AS THE *UN-REVEALED* STATE, not as a pair of rules.
   The obvious version — .reveal{transform:...} plus .reveal.d3-in{transform:none}
   — silently killed every other transform on this sheet: half the elements that
   drift, lay flat or tilt are ALSO .reveal, and "transform:none" at equal
   specificity but later source order won every one of those fights. Stating
   only the not-yet-arrived pose means the depth transforms simply take over the
   moment the element lands, with the transition above carrying it across. */
html.d3 .reveal:not(.d3-in){
  opacity:0;
  transform:translate3d(0,22px,-70px) rotateX(3.5deg);
  filter:blur(3px);
}

/* ---------------------------------------------------------------------------
   9. THE FAR WALL — the footer is the furthest thing in the room
--------------------------------------------------------------------------- */
html.d3 .footer{
  box-shadow:inset 0 24px 40px -30px rgba(0,0,0,1);
  filter:brightness(.94);
}

/* ---------------------------------------------------------------------------
   10. THE PREVIEW CONTROL — not part of the design, only of the experiment
--------------------------------------------------------------------------- */
.d3-ui{
  position:fixed;left:18px;bottom:18px;z-index:200;
  display:flex;align-items:center;gap:12px;
  padding:10px 14px;border:1px solid var(--line-strong);border-radius:var(--r-pill);
  background:rgba(20,20,20,.88);backdrop-filter:blur(14px);
  box-shadow:0 22px 44px -22px rgba(0,0,0,1),inset 0 1px 0 rgba(255,255,255,.07);
  font-family:var(--font-data);font-size:10px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--text-secondary);user-select:none;
}
.d3-ui b{color:var(--text-primary);font-weight:600}
.d3-ui button{
  font:inherit;letter-spacing:.12em;text-transform:uppercase;cursor:pointer;
  padding:5px 12px;border-radius:var(--r-pill);border:1px solid var(--line-strong);
  background:var(--surface-raised);color:var(--text-secondary);
}
.d3-ui button.is-on{background:var(--select);border-color:var(--select);color:var(--text-on-select)}
.d3-ui input[type=range]{width:104px;accent-color:var(--select);cursor:pointer}
.d3-ui kbd{
  font-family:var(--font-data);font-size:9px;padding:2px 5px;border-radius:3px;
  border:1px solid var(--line-strong);background:var(--surface-base);color:var(--text-faint);
}
@media (max-width:760px){ .d3-ui__hint{display:none} }

/* ---------------------------------------------------------------------------
   11. REDUCED MOTION
   Depth is not motion. Someone who has asked for less movement still gets the
   shadows, the recession and the layering — they just stop being animated.
--------------------------------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  html.d3 .reveal:not(.d3-in){opacity:1;transform:none;filter:none}
  html.d3 .reveal{transition:none}
  html.d3 .d3-persp .stage__wrap,
  html.d3 .d3-lay > .frame,
  html.d3 .hero__copy,html.d3 .hero__grid,
  html.d3 [data-d3-drift],
  .d3-atmos > div{transform:none !important;transition:none !important}
  html.d3 .d3-tile,html.d3 .desk__cell{transition:none}
}
