.jcd-disco-host{position:relative!important;isolation:isolate;touch-action:pan-y;--jcd-disco-width:650px}
.jcd-disco-host.jcd-disco-full-bleed{box-sizing:border-box!important;width:100vw!important;max-width:none!important;min-height:calc(100vh + var(--jcd-disco-top-inset,0px))!important;margin-top:calc(-1 * var(--jcd-disco-top-inset,0px))!important;margin-left:calc(50% - 50vw)!important;margin-right:calc(50% - 50vw)!important}
.jcd-disco-host>.jcd-disco-wrap{position:absolute;inset:0;z-index:1;display:grid;place-items:center;pointer-events:none;overflow:hidden}
.jcd-disco-host>.jcd-disco-wrap>.jcd-disco-background{position:absolute;inset:0;z-index:0;overflow:hidden;background:#020201;pointer-events:none}
.jcd-disco-host>.jcd-disco-wrap>.jcd-disco-background>video{display:block;width:100%;height:100%;object-fit:cover;object-position:center;pointer-events:none}
.jcd-disco-host>.jcd-disco-wrap>.jcd-disco-stage{position:relative;z-index:1;box-sizing:border-box;width:min(var(--jcd-disco-width,650px),100%);height:auto;max-width:100%;aspect-ratio:1/1;flex:none;pointer-events:none;overflow:visible}
.jcd-disco-host>.jcd-disco-wrap>.jcd-disco-stage>.jcd-disco-canvas{display:block;position:absolute;width:100%;height:100%;z-index:1;background:transparent!important;pointer-events:none}
.jcd-disco-host>.elementor-element,.jcd-disco-host>.e-con-inner,.jcd-disco-host>.elementor-container{position:relative;z-index:2}


/* Beta 3: native Elementor container is the scene host. */
.elementor-element.jcd-disco-host {
    position: relative !important;
    isolation: isolate;
}
.elementor-element.jcd-disco-host > .jcd-disco-wrap {
    z-index: 0;
}
.elementor-element.jcd-disco-host > .e-con-inner,
.elementor-element.jcd-disco-host > .elementor-element,
.elementor-element.jcd-disco-host > .elementor-container {
    position: relative;
    z-index: 1;
}

/* The first frames are drawn before the scene is configured and lit, so hold
   the canvas transparent until the renderer reports a painted frame.
   The reveal is a CUT, not a fade, and that is the fix for the olive flash --
   see the note below. */
.jcd-disco-host>.jcd-disco-wrap>.jcd-disco-stage>.jcd-disco-canvas{opacity:0}
.jcd-disco-host[data-jcd-disco-painted="1"]>.jcd-disco-wrap>.jcd-disco-stage>.jcd-disco-canvas{opacity:1}

/* THE OLIVE FLASH.
   Holding the canvas was not enough, because the olive was never the canvas.
   The background layer is a DOM div, and the adapter writes the scene's
   background gradient onto it INLINE as soon as the payload is read -- the
   second stop is backgroundColorB, olive by default. That div paints on the
   very first layout pass while the WebGPU canvas is still compiling shaders,
   so the olive is on screen alone for as long as that takes.
   Suppress the gradient until the scene has actually PAINTED and show the base
   near-black instead. The gate is data-jcd-disco-painted, set by the renderer
   after its first submitted frame -- NOT data-djjc-state="mounted", which the
   first version of this used. "Mounted" means the host element mounted, which
   happens long before WebGPU has compiled a shader, so that gate released the
   gradient while the canvas was still blank and the flash survived a fix that
   measured correct in every static check.
   !important is required and is not a shortcut: the gradient is an inline
   style, and an inline declaration is only beaten by an important one. The
   colour must be restated because the inline `background` shorthand resets
   background-color to transparent on its way to setting the image.

   WHY THE CANVAS REVEAL ABOVE IS A CUT AND NOT A FADE.
   Gating on the painted frame was right; fading the canvas in was what kept
   the flash alive. Both the gradient release and the canvas reveal key on
   data-jcd-disco-painted, but the release is instant and the fade was .22s, so
   the attribute uncovered a full-strength olive gradient and then took 220ms to
   put anything on top of it. A per-frame trace of the real load caught it:

       181 ms  painted=-  background rgb(2,2,1)  canvas opacity 0
       376 ms  painted=1  background GRADIENT    canvas opacity 0     <- flash
       451 ms  painted=1  background GRADIENT    canvas opacity 0.55
       582 ms  painted=1  background GRADIENT    canvas opacity 1

   206 ms of bare olive with nothing drawn over it. The fade did not soften the
   flash, it WAS the flash. Removing the transition makes the reveal atomic:
   the gradient and the finished canvas turn on in the same style recalc, so
   there is no frame in which one is visible without the other. */
.jcd-disco-host:not([data-jcd-disco-painted="1"])>.jcd-disco-wrap>.jcd-disco-background{background-image:none!important;background-color:#020201!important}

/* THE LOADING PLACEHOLDER.

   What data-jcd-disco-painted now means changed on 2026-08-01. It used to be
   set on the renderer's first submitted frame; it is now set by the loading
   gate, which additionally waits for the environment map to be bound, the room
   textures to be decoded, the logo to have resolved and the first optical solve
   to have completed. The measured gap between those two moments at 390x844 over
   Slow 4G was 316.6 ms and 38 presented frames of matte-grey mirrors on
   untextured concrete. See sceneReadiness() in disco-ball.js.

   ALL THREE RULES KEYED ON THIS ATTRIBUTE ARE CUTS. Nothing here may carry a
   transition or an animation. The olive flash survived a correct gate exactly
   once before, because the gradient was released instantly while the canvas
   faded in over .22s -- the fade was not softening the flash, the fade WAS the
   flash. Placeholder off, canvas opaque and gradient released all land in one
   style recalc, so there is no frame in which any of them is visible without
   the others.

   JOHN HAS NOT DESIGNED THIS YET and asked only for "a simple loading
   placeholder... for now". It is therefore deliberately opinionless: the
   scene's own authored base near-black, and one static hairline ring on the
   ball's own centre line so a slow connection reads as waiting rather than as
   broken. No brand, no copy, no progress bar, no motion.

   TO REPLACE IT: this block is the whole of it. The element is an empty
   aria-hidden div, .jcd-disco-placeholder, and nothing in the renderer reads
   its contents. --jcd-disco-placeholder-mark sets the ring's colour; set it to
   transparent for a bare field.

   COOKIE CONSENT SEAM -- WPConsent / WP Consent API are live on the site and
   their copy and layout are out of scope here. The hook they should use is the
   djjc:scene-ready event, which bubbles from the host and carries
   { sceneId, openedBy, readiness }. A banner keyed on that appears with the
   hero instead of over a placeholder. Do not key consent UI on this attribute
   directly and do not put consent markup inside .jcd-disco-placeholder -- the
   placeholder is display:none the instant the gate opens. */
.jcd-disco-host>.jcd-disco-wrap>.jcd-disco-placeholder{position:absolute;inset:0;z-index:2;display:grid;place-items:center;pointer-events:none;background:#020201;--jcd-disco-placeholder-mark:rgba(255,255,255,.07)}
.jcd-disco-host>.jcd-disco-wrap>.jcd-disco-placeholder::after{content:"";display:block;width:min(38vmin,220px);aspect-ratio:1/1;border-radius:50%;border:1px solid var(--jcd-disco-placeholder-mark)}
.jcd-disco-host[data-jcd-disco-painted="1"]>.jcd-disco-wrap>.jcd-disco-placeholder{display:none}
