/* ═══════════════════════════════════════════════════════════════
   ZERONIQ Section — container widget with 6 background modes
   Base structure:
     .zsec-wrap        outer positioning + min-height
       .zsec-bg        absolute background layer (color / gradient / canvas)
         .zsec-canvas  WebGL canvas for mesh + lines modes
         .zsec-overlay optional dark tint for image mode
       .zsec-content   flex column holding user-dropped Elementor content
   ═══════════════════════════════════════════════════════════════ */

.zsec-wrap {
    position: relative;
    display: block;
    width: 100%;
    isolation: isolate;
    overflow: hidden;
    /* Establishes a container query context so descendants can size in cqw
       (1% of this wrap's width) instead of vw. Text Glow uses this — the
       Elementor editor preview iframe is narrower than the live viewport
       (sidebar eats width), so vw-based sizing diverged between edit and
       frontend. cqw scales to the section itself in both environments. */
    container-type: inline-size;
    /* min-height set via Elementor inline selector */
}

/* Full-bleed: widget breaks out of parent container to span 100vw.
   Trick: 100vw wide, negative margin equal to (viewport half - parent half)
   pulls widget left so it starts at viewport edge. Requires
   html/body overflow-x: hidden (Elementor default). Also zero out the
   Elementor widget wrapper padding + parent container's inline padding
   so nothing eats the edges.

   Elementor's widget-class prefix uses the widget's get_name() output.
   Some Elementor versions have converted underscores to hyphens in the
   CSS class — we cover both `zerova_section` and `zeroniq-section` so
   the rule always matches regardless. */
.zsec-fb-yes.elementor-widget-zerova_section,
.elementor-widget-zerova_section.zsec-fb-yes,
.zsec-fb-yes.elementor-widget-zeroniq-section,
.elementor-widget-zeroniq-section.zsec-fb-yes,
.zsec-fb-yes[class*="elementor-widget-zeroniq"] {
    width: 100vw;
    max-width: 100vw;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
    padding: 0 !important;
}
.zsec-fb-yes .zsec-wrap {
    width: 100vw;
    max-width: 100vw;
}

.zsec-bg {
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    /* Canvas modes need a solid backdrop so first frame isn't transparent. */
}
/* Canvas modes need a solid backdrop so first frame isn't transparent. */
.zsec-wrap[data-bg="mesh"]     .zsec-bg,
.zsec-wrap[data-bg="lines"]    .zsec-bg,
.zsec-wrap[data-bg="kinetic"]  .zsec-bg,
.zsec-wrap[data-bg="neural"]   .zsec-bg,
.zsec-wrap[data-bg="ink"]      .zsec-bg,
.zsec-wrap[data-bg="neonflow"] .zsec-bg { background: #0A0B0F; }
.zsec-wrap[data-bg="kinetic"] .zsec-bg { background: #161618; }

/* ─────── Background DM/LM Sync ───────
   When the widget is set to sync solid or gradient backgrounds with the
   global theme toggle, both DM and LM values are inlined as CSS vars on
   the wrap (--zsec-bg-dm + --zsec-bg-lm). We can't just redefine
   --zsec-bg-dm inside html[data-theme=light] — inline CSS-var declarations
   win over stylesheet declarations of the same property. So instead the
   selector itself changes which var is painted: base rule uses -dm, LM
   override rule uses -lm. Solid uses background-color to keep normal color
   inheritance; gradients use the shorthand `background`. */
.zsec-wrap[data-bg-sync="1"][data-bg="solid"] .zsec-bg {
    background-color: var(--zsec-bg-dm);
}
.zsec-wrap[data-bg-sync="1"][data-bg="gradient_linear"] .zsec-bg,
.zsec-wrap[data-bg-sync="1"][data-bg="gradient_radial"] .zsec-bg {
    background: var(--zsec-bg-dm);
}
html[data-theme="light"] .zsec-wrap[data-bg-sync="1"][data-bg="solid"] .zsec-bg {
    background-color: var(--zsec-bg-lm);
}
html[data-theme="light"] .zsec-wrap[data-bg-sync="1"][data-bg="gradient_linear"] .zsec-bg,
html[data-theme="light"] .zsec-wrap[data-bg-sync="1"][data-bg="gradient_radial"] .zsec-bg {
    background: var(--zsec-bg-lm);
}

/* ─────── Infinite grid: SVG-based, no WebGL. ─────── */
.zsec-infinite {
    position: absolute;
    inset: 0;
    overflow: hidden;
}
.zsec-infinite__base,
.zsec-infinite__spot {
    position: absolute;
    inset: 0;
    background-image: var(--zsec-inf-grid);
    background-size: 40px 40px;
    background-position: 0 0;
    will-change: background-position;
}
.zsec-infinite__base { opacity: 0.05; }
.zsec-infinite__spot {
    opacity: 0.4;
    /* Radial mask that follows cursor, updated via CSS vars from JS. */
    -webkit-mask-image: radial-gradient(300px circle at var(--zsec-mx, 50%) var(--zsec-my, 50%), #000, transparent);
            mask-image: radial-gradient(300px circle at var(--zsec-mx, 50%) var(--zsec-my, 50%), #000, transparent);
}
/* Colored glow blobs in corners. */
.zsec-infinite__glow {
    position: absolute;
    border-radius: 50%;
    filter: blur(120px);
    opacity: 0.4;
    pointer-events: none;
}
.zsec-infinite__glow--tr  { top: -20%; right: -20%; width: 40%; height: 40%; }
.zsec-infinite__glow--tr2 { top: -10%; right:  10%; width: 20%; height: 20%; opacity: 0.3; filter: blur(100px); }
.zsec-infinite__glow--bl  { bottom: -20%; left: -10%; width: 40%; height: 40%; }

.zsec-canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;
}

.zsec-overlay {
    position: absolute;
    inset: 0;
    z-index: 1;
}

/* ─────── Text Glow Overlay ───────
   Sits between background (z:0) and content (z:2). Renders only when
   the widget has data-tg="1" — no CSS cost when disabled. */
.zsec-textglow {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
/* SVG height comes from --tg-size (cqw = 1% of section width) — decouples
   text size from the ZERONIQ Content section height, and stays proportional
   across the Elementor editor iframe and the live viewport (which differ
   in absolute pixel width). Width is auto-derived from the viewBox aspect
   (600:100 = 6:1) so height * 6 = width. If the wrap is narrower, the SVG
   overflows horizontally and gets clipped by wrap's overflow:hidden
   (equal-sided crop because of flex centering). Height stays exact. */
.zsec-textglow__svg {
    height: var(--tg-size, 20cqw);
    display: block;
    flex-shrink: 0;
}
/* Default typography — overridden by Elementor's Group_Control_Typography
   whenever the user picks a font in the widget panel. Kept as sensible
   fallback so the widget looks reasonable out of the box. font-size stays
   in the inline style attribute of the text (100px = viewBox height) so
   Elementor can freely override family/weight/spacing/transform without
   touching the height mechanic. */
.zsec-textglow__svg text {
    font-family: "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0;
}
/* ─────── Text Glow DM/LM Sync ───────
   Inline styles emit -dm and -lm suffixed vars only. CSS rules below
   determine which suffix populates the "active" (--tg-stroke, --tg-c1..3)
   vars that the SVG actually reads. This detour is necessary because
   inline CSS-var declarations override same-name declarations in a
   stylesheet — so if we set --tg-stroke inline, the LM rule below wouldn't
   be able to swap it. With separate suffixes, this rule is the ONLY source
   of --tg-stroke, so LM cleanly wins under html[data-theme=light]. */
.zsec-wrap[data-tg="1"] {
    --tg-stroke: var(--tg-stroke-dm);
    --tg-c1: var(--tg-c1-dm);
    --tg-c2: var(--tg-c2-dm);
    --tg-c3: var(--tg-c3-dm);
}
html[data-theme="light"] .zsec-wrap[data-tg-sync="1"] {
    --tg-stroke: var(--tg-stroke-lm);
    --tg-c1: var(--tg-c1-lm);
    --tg-c2: var(--tg-c2-lm);
    --tg-c3: var(--tg-c3-lm);
}
/* Optional hide-on-mobile (recommended for perf + legibility). */
@media (max-width: 768px) {
    .zsec-wrap[data-tg-hide-mobile="1"] .zsec-textglow { display: none; }
}

/* ─────── Sticky Aura (v3.3.626) ───────
   Aura stays pinned inside the viewport while section content scrolls
   over it. Only active when tg_sticky control is on.

   DOM structure change vs. non-sticky mode: PHP render() places .zsec-textglow
   as FIRST CHILD of .zsec-content (not as sibling of it). This anchors the
   sticky element to the content flow itself — sticky engages the moment the
   content-container top crosses the header, not the section-wrap top. Prevents
   the "empty aura at section entry" bug from v3.3.625, where aura stuck to
   the wrap top while content was still further down inside its own padding.

   Why `overflow: clip` on the wrap: overflow:hidden creates a scroll-containing
   block, which anchors sticky descendants to the wrap itself — since the wrap
   moves with the page, sticky descendants would just move with it (net zero
   sticky). `overflow: clip` clips visually WITHOUT establishing a scroll-
   containing block, so sticky resolves against page scroll and actually sticks.
   Full-bleed clipping (100vw + negative margin) remains intact under `clip`.
   Browser support: Chrome 90+, Safari 16+, Firefox 81+ — all modern engines.

   `inset: auto` explicitly resets the base rule's inset:0, THEN we set
   position + top. Order matters — inset shorthand after top would wipe top
   back to auto (sticky requires an explicit anchor to work).

   top uses --zvhb-h so aura sits below the sticky header. Height is
   100vh - header — aura fills the visible viewport area perfectly. Existing
   tg_v_align (align-items) still positions the SVG inside this 100vh sticky
   window (top/middle/bottom of the visible fold).

   margin-bottom pulls the layout impact back to zero so aura doesn't push
   Elementor content down (aura occupies zero layout space, only paints).

   z-index:0 + aura as first DOM child of .zsec-content: subsequent content
   siblings (which default to z-index:auto but come later in DOM order) paint
   on top. If a content sibling has position:relative + higher z-index it'll
   still paint over aura correctly.

   pointer-events:none because aura is decorative — clicks pass through to
   whatever content sits over it. */
.zsec-wrap[data-tg="1"][data-tg-sticky="1"] {
    overflow: clip;
}
.zsec-wrap[data-tg="1"][data-tg-sticky="1"] .zsec-content > .zsec-textglow {
    inset: auto;
    position: sticky;
    top: var(--zvhb-h, 0px);
    height: calc(100vh - var(--zvhb-h, 0px));
    width: 100%;
    margin-bottom: calc(-1 * (100vh - var(--zvhb-h, 0px)));
    pointer-events: none;
    z-index: 0;
}
/* On pages with header hidden (zvhb-no-header), --zvhb-h is nulled to 0
   by the page-header suppression CSS, so top/height fall back correctly
   to full viewport — no special-casing needed here. */

.zsec-content {
    position: relative;
    z-index: 2;
    width: 100%;
    /* Layout (padding, alignment, columns, gap, flex/grid direction, wrap,
       responsive breakpoints) is handled by the Elementor Container inside.
       Zero-config here so Elementor's controls take over cleanly. */
    min-height: inherit;
}

/* Reduced motion: freeze canvas animations. Handled in JS too, but CSS
   provides a visual cue if JS hasn't started yet. */
@media (prefers-reduced-motion: reduce) {
    .zsec-canvas { animation: none !important; }
}

/* Mobile: ensure background canvas resizes cleanly when viewport rotates. */
@media (max-width: 600px) {
    .zsec-canvas { image-rendering: auto; }
}
