/* =========================================
   PANEL MOTION

   The violet capability panels are the
   largest flat areas on the site - a big
   block with a long gap down the left and
   three items stacked on the right. Two
   pieces of motion, both restrained:

   1. Ambient light drifting inside the
      panel, slow enough (26s) to read as
      depth rather than as something moving.

   2. The contents arrive when the panel is
      scrolled to, staggered in reading
      order. It fires once and never repeats -
      a reveal that replays every time you
      scroll past stops being a reveal.

   Built so it cannot fail badly: the visible
   end state is the CSS default, and the
   hidden start state is only applied by the
   script itself. A blocked script, or a
   browser without IntersectionObserver,
   leaves the panel reading exactly as it
   does now.
   ========================================= */

.elementor .elementor-element-2265245,
.elementor .elementor-element-503ca20 {
    position: relative;

    /* The drifting light is inset -22%, so it has to be clipped back to the
       rounded panel. This was overflow: hidden, which was wrong: an ancestor
       with a non-visible overflow becomes the scroll container for anything
       inside it, and the heading block in the left column is position: sticky.
       It stopped sticking and simply scrolled away with the panel.

       clip-path cuts the light to the same rounded box without creating a
       scroll container, so the heading pins again. Measured: with overflow
       the heading held a constant 68px from the panel top through the whole
       scroll; with clip-path it travels and parks at its declared 20px. */
    clip-path: inset(0 round 24px);
}

@media (max-width: 767px) {
    /* matching the smaller radius the panel takes at this width */
    .elementor .elementor-element-2265245,
    .elementor .elementor-element-503ca20 {
        clip-path: inset(0 round 18px);
    }
}

/* ---- 1. ambient light ---------------------------------------- */
.elementor .elementor-element-2265245::before,
.elementor .elementor-element-503ca20::before {
    content: "";
    position: absolute;
    inset: -22%;
    pointer-events: none;
    z-index: 0;
    background:
        radial-gradient(ellipse 40% 48% at 20% 26%, rgba(163, 104, 255, .32), transparent 66%),
        radial-gradient(ellipse 36% 42% at 80% 72%, rgba(101, 40, 200, .28), transparent 64%);
    animation: dni-panel-drift 26s ease-in-out infinite alternate;
}

@keyframes dni-panel-drift {
    0%   { transform: translate3d(-2.5%, -1.5%, 0) scale(1); }
    50%  { transform: translate3d( 1.5%,  2%,   0) scale(1.06); }
    100% { transform: translate3d( 3%,   -2%,   0) scale(1.02); }
}

/* the panel's own content sits above the light */
.elementor .elementor-element-2265245 > *,
.elementor .elementor-element-503ca20 > * {
    position: relative;
    z-index: 1;
}

/* ---- 2. staggered reveal -------------------------------------- */
.dni-panel-armed .dni-reveal {
    opacity: 0;
    transform: translateY(16px);
}

.dni-panel-armed.is-in .dni-reveal {
    opacity: 1;
    transform: none;
    transition: opacity .6s cubic-bezier(.22, 1, .36, 1),
                transform .6s cubic-bezier(.22, 1, .36, 1);
    transition-delay: calc(var(--i, 0) * 95ms);
}

@media (prefers-reduced-motion: reduce) {
    .elementor .elementor-element-2265245::before,
    .elementor .elementor-element-503ca20::before { animation: none; }

    .dni-panel-armed .dni-reveal,
    .dni-panel-armed.is-in .dni-reveal {
        opacity: 1;
        transform: none;
        transition: none;
    }
}

/* ---- 3. the capability rules --------------------------------- */
/* Each item's border-left shipped as #333 - a dark grey hairline on a
   violet panel, which read as a seam rather than as a mark. Replaced with
   a brand rule that draws itself downward as the panel arrives, so the
   items feel written in rather than simply present.

   The original border is kept in the layout and made transparent, rather
   than removed: it is what reserves the space, and taking it away would
   shift every item left by 3px. */
.dni-rule {
    position: relative;
    border-left-color: transparent !important;
}

.dni-rule::before {
    content: "";
    position: absolute;
    left: -3px;
    top: 0;
    bottom: 0;
    width: 3px;
    border-radius: 3px;
    background: linear-gradient(180deg,
        #C9A9FF 0%, #7E29FE 42%, rgba(126, 41, 254, .28) 100%);
    transform-origin: top center;
    transition: box-shadow .28s ease-out;
}

.dni-panel-armed .dni-rule::before { transform: scaleY(0); }

.dni-panel-armed.is-in .dni-rule::before {
    transform: scaleY(1);
    transition: transform .75s cubic-bezier(.22, 1, .36, 1),
                box-shadow .28s ease-out;
    /* after the copy has begun arriving, so the rule draws alongside it
       rather than racing ahead */
    transition-delay: calc(var(--ri, 0) * 150ms + 220ms);
}

/* ---- the beat -----------------------------------------------
   Once the rule has drawn itself it keeps a pulse: two beats close
   together and then a rest, which is the shape of a heartbeat rather than
   the even throb of a loading bar. A single sine would read as breathing;
   it is the pause that makes it a beat.

   The stagger is small and deliberate - .14s apart, so the pulse appears
   to travel down the column instead of every rule strobing at once.

   Only after the reveal finishes: a rule that beats while it is still
   drawing itself fights its own animation. */
/* @keyframes dni-rule-beat now lives in dni-section-design.css, which
   every page loads - use-cases uses the same beat and does not load this
   file, so defining it here made the animation resolve to nothing there. */

.dni-panel-armed.is-in .dni-rule::before {
    animation: dni-rule-beat 2.1s ease-in-out infinite;
    /* clears the staggered draw-down before the beat starts */
    animation-delay: calc(var(--ri, 0) * .14s + 1.15s);
}

/* the item under the cursor lights its own rule, and holds it lit */
@media (hover: hover) {
    .dni-rule:hover::before {
        animation-play-state: paused;
        opacity: 1;
        box-shadow: 0 0 16px rgba(154, 92, 254, .75);
    }
}

@media (prefers-reduced-motion: reduce) {
    .dni-panel-armed .dni-rule::before,
    .dni-panel-armed.is-in .dni-rule::before {
        transform: scaleY(1);
        transition: none;
        animation: none;
        opacity: 1;
    }
}
