/* ==========================================================================
   DIVLAB WORKS — layout sync for the liquid hover canvas
   --------------------------------------------------------------------------
   Scoped entirely to the works section's own classes. No resets, no element
   selectors, nothing global — safe to paste into Elementor's Custom CSS or
   to enqueue from the child theme.
   ========================================================================== */

/* The canvas is absolutely positioned INSIDE the section, so it scrolls with
   the section and the plane coordinates stay valid without recomputing them
   on every scroll event. That requires a positioned ancestor. */
.dvl-works {
  position: relative;

}

/* ==== THE FIRST LEG OF THE RAMP — see dvl-services.css for the whole ======
   This section has never had a background of its own. Measured on the live
   page it computes to rgba(207,63,205,0) — fully transparent — so what the
   visitor reads as "the works background" is actually dvl-stage.js's fixed
   canvas showing through, and that canvas is still carrying the warm tint
   section 2 leaves behind. The colour therefore drifted with scroll position
   and then stepped hard into the services section.

   THE TOP EDGE FADES IN FROM NOTHING. rgba(235,234,232,0) — the same rgb at
   zero alpha, never the keyword `transparent`, which is rgba(0,0,0,0) and
   ramps through a dirty grey band on the way. Starting transparent lets
   whatever section 2 left on the canvas bleed into this section instead of
   meeting a line, the same technique paintBackground() uses at the services
   boundary.

   32vh, not a percentage: the fade has to read the same on a short phone and
   a tall desktop, and this section's height varies with the number of cards.

   The bottom stop is --dvl-tone-mid, exactly where the services section
   starts. That join is a continuation, not a transition.

   ---- WHY AN ID SELECTOR AND !important, WHICH THIS FILE OTHERWISE AVOIDS --
   Two rules on the live page set background-image with !important on this
   element, and a plain `.dvl-works` (0,1,0) loses to both:

     reset.css        *, ::after, ::before { background-image: initial
                      !important }
     Elementor        .e-con.e-parent:nth-of-type(n+3):not(.e-lazyloaded)
                      :not(.e-no-lazyload) { background-image: none
                      !important }

   The second is Elementor's container background LAZY-LOADING: it suppresses
   background images on below-the-fold containers until it adds
   .e-lazyloaded. Sensible for a photograph; pointless for a gradient, which
   costs no request. An ID (1,0,0) outranks both, and !important is required
   to compete at all since theirs carry it.

   Verified on the live page: without this the computed value was `none`. */
#dvl-works {
  background-image: linear-gradient(
    to bottom,
    rgba(235, 234, 232, 0) 0,
    var(--dvl-tone-top, #ebeae8) 32vh,
    var(--dvl-tone-top, #ebeae8) 62%,
    var(--dvl-tone-mid, #eae9e7) 100%
  ) !important;
  padding-top: clamp(100px, 18vh, 180px) !important;
}

.dvl-works__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 1;
  /* Essential. Hover is detected on the DOM item underneath, and Elementor's
     own links inside each card have to stay clickable. */
  pointer-events: none;
}

/* ==========================================================================
   NON-CARD CONTENT SITS ABOVE THE CANVAS
   --------------------------------------------------------------------------
   Section headings, intro copy, a "view all" link — anything in the section
   that is not a card. The canvas is absolutely positioned at z-index 1 and
   is the LAST child, so a static, unpositioned heading paints beneath it.

   In practice the canvas is transparent wherever no card is drawn, so such a
   heading is usually still visible — measured on the live page it computed
   to opacity 1 / visibility visible. But "usually" is not a guarantee, and
   it costs nothing to put them definitively on top.

   Direct children only: raising the top-level wrapper lifts everything
   inside it with one stacking context, rather than fighting Elementor for
   every nested widget.
   ========================================================================== */
.dvl-works > *:not(.dvl-works__canvas):not(.dvl-work-item) {
  position: relative;
  z-index: 10;
  opacity: 1;
  pointer-events: auto;
}

/* Each card is the hover target and the measuring reference. */
.dvl-work-item {
  position: relative;
}

/* ==========================================================================
   THE EDITORIAL RAILS — four different card widths, two alignment rails
   --------------------------------------------------------------------------
   Read off HOME 5 in Figma. At the 1920 frame the four card images are

     Div 01   1426 x 802    x  78 .. 1504
     Div 02   1088 x 1088   x 416 .. 1504
     Div 03   1426 x 802    x 414 .. 1840
     Div 04   1758 x 1088   x  82 .. 1840

   which is NOT four arbitrary numbers. The right edges pair up exactly —
   cards 1 and 2 both stop at 1504, cards 3 and 4 both stop at 1840 — and
   1840 is the 80px gutter line. Measured against the 1760px content box
   between the gutters (x 80 .. 1840) the whole section collapses to three
   percentages and nothing else:

     card 1   width 81%                  right rail 81%
     card 2   width 62%   left rail 19%  right rail 81%   (19 + 62 = 81)
     card 3   width 81%   left rail 19%  right rail 100%  (19 + 81 = 100)
     card 4   width 100%                 right rail 100%

   Two right rails at 81% and 100%, one left rail at 19%, and card 4
   spanning the full content box. That is the composition.

   WHAT WAS BUILT INSTEAD. Every image rendered at exactly 900px — Elementor
   has the image widget on "Inline (auto)" (.elementor-widget__width-initial,
   align-self: flex-start), so each one shrink-wrapped to the same authored
   size and the variation disappeared. Measured live at 1920 the right edges
   came out 1172 / 1538 / 1390 / 1015: no rails at all, just four equal boxes
   at four unrelated offsets. The aspect ratios were always correct, so this
   is purely scale and placement.

   WHY PERCENTAGES AND NOT PIXELS. They are percentages in the design too —
   the numbers above are what 81/62/19 resolve to at 1920. Expressed this way
   the rails survive every viewport without a second set of breakpoints, and
   the tablet requirement ("same design, adjusted sizes") is satisfied for
   free rather than needing its own block.

   WHY align-self. The cards are flex items in a column container and
   Elementor sets align-self: center on each. Centring and an explicit
   margin-left fight: the margin would be added to a box that is then
   re-centred, so the rails would land somewhere between the two. flex-start
   makes margin-left mean "distance from the container's left edge", which is
   what the rails are.

   WHY !important. Elementor writes these as per-element rules
   (.elementor-221 .elementor-element.elementor-element-2100c0e), which ties
   or beats a plain attribute selector. Same reason the mobile block at the
   foot of this file carries them.

   data-dvl-card is stamped by dvl-works.js, not authored in Elementor. CSS
   has no "nth element matching this class" selector — :nth-of-type counts by
   TAG among siblings, and these cards share their tag with the heading
   wrapper, the explore block and the canvas, so it would number them wrong.
   The stamp runs before the WebGL bail, so it lands even where the canvas
   never starts.
   ========================================================================== */
@media (min-width: 768px) and (min-height: 521px) {
  .dvl-work-item[data-dvl-card] {
    align-self: flex-start !important;
    margin-right: 0 !important;
  }

  .dvl-work-item[data-dvl-card="1"] { width: 81%  !important; margin-left: 0   !important; }
  .dvl-work-item[data-dvl-card="2"] { width: 62%  !important; margin-left: 19% !important; }
  .dvl-work-item[data-dvl-card="3"] { width: 81%  !important; margin-left: 19% !important; }
  .dvl-work-item[data-dvl-card="4"] { width: 100% !important; margin-left: 0   !important; }

  /* ---- THE VERTICAL RHYTHM ---------------------------------------------
     The design breathes far more than the build did. Measured between card
     IMAGE edges in HOME 5: 223, 223, 215 — call it 220 at the 1920 frame.
     Measured on the live page: 20, 20, 20.

     That 20 was not a spacing decision at all. `.dvl-works` is itself the
     flex column holding the heading, the four cards, the CTA and the
     canvas, and it carries Elementor's default `row-gap: 20px`. Nothing
     else contributed — every card computed margin-bottom: 0px.

     So the gap is zeroed at source and rebuilt as explicit card margins.
     Setting the container's row-gap to 220 instead would have been shorter,
     but it also spaces the heading block and the CTA, which want different
     numbers — the heading already carries its own internal padding, and the
     CTA's margins are set in Elementor and belong to the editor.

     Fluid, not fixed: 11.46vw is 220px at 1920, so the rhythm scales with
     the rails rather than stranding a desktop number on a tablet. Both
     values are exposed as custom properties — override them anywhere above
     this in the cascade without touching the file. */
  .dvl-works {
    row-gap: 0 !important;
  }

  .dvl-work-item[data-dvl-card] {
    margin-top: 0 !important;
    margin-bottom: var(--dvl-works-card-gap, clamp(80px, 11.46vw, 220px)) !important;
  }

  /* The lede sits closer than a full card gap because the heading block
     brings ~67px of its own bottom padding with it. Measured to the bottom
     of "Selected Divs", the design wants ~242px of air before the first
     artwork; this is the remainder. */
  .dvl-work-item[data-dvl-card="1"] {
    margin-top: var(--dvl-works-lede-gap, clamp(56px, 9.1vw, 175px)) !important;
  }

  /* The last card hands off to the CTA, whose own margins are authored in
     Elementor. Adding to them here would mean the same gap is set in two
     places and drifts the first time either is touched. */
  .dvl-work-item[data-dvl-card="4"] {
    margin-bottom: 0 !important;
  }

  /* ---- THE LEDE SITS ON THE GRID LINE TOO ------------------------------
     #dvl-works carries the site's 80px gutter and the cards honour it, but
     the heading block does not: its Elementor wrapper arrives with the
     default 10px side padding, so "Selected Divs" and <DIV-BOX> rendered at
     x 90 while every card sat at 80 — and the header logo at 80.

     Ten pixels, but it is the one line the eye checks a layout against, and
     it read as the whole section being off.

     :not(.dvl-work-item) keeps this away from the cards, whose own left
     offsets are the editorial rails set above and must not be flattened. */
  #dvl-works > .e-con-full:not(.dvl-work-item) {
    padding-left: 0 !important;
    padding-right: 0 !important;
  }

  /* Release the image widget so the artwork actually fills the rail the card
     now defines. Without this the card widens and the 900px image simply
     sits inside it at the left, which looks like nothing changed.

     :has(> img) resolves to the image widget's own wrapper — the one
     carrying .elementor-widget__width-initial — without hard-coding an
     Elementor class name that a version bump could rename. */
  .dvl-work-item[data-dvl-card] *:has(> img) {
    width: 100% !important;
    max-width: none !important;
    align-self: stretch !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
  }
}

/* The <img> defines the layout box the WebGL plane copies. It must occupy
   real space even after it is hidden, or the plane would be measured against
   a collapsed box. */
.dvl-work-item img {
  display: block;
  width: 100%;
  height: auto;
}

/* ONLY once every texture has decoded does the section go "live" and the DOM
   images step aside. `visibility: hidden` rather than `display: none` — the
   element keeps its box, so getBoundingClientRect() still returns the real
   geometry the shader planes are built from.

   If WebGL fails, or a texture never loads, this class is never added and the
   images simply stay visible. The section degrades to a plain image grid. */
.dvl-works--live .dvl-work-item img {
  visibility: hidden;
}

/* Card labels ("Div 01", "<Inflow>", the description) stay as DOM text above
   the canvas: crisp, selectable, readable by search engines, and — matching
   the reference frames — undistorted while the image ripples beneath them.

   ABSOLUTE, not relative. Relative would leave the block in normal flow, so
   it stacks BELOW the image instead of over it. Absolute lifts it out of
   flow and onto the card, which also means the card's height is set purely
   by the image — exactly the box the WebGL plane is measured from.

   The image keeps its box even when hidden (visibility, not display), so
   `inset: 0` resolves against the real card geometry. */
.dvl-work-item__content {
  /* Position only. The BOX — left, top, width, height — is written by
     placeContent() in dvl-works.js, measured from the image itself.

     `inset: 0` used to live here and it does not work in Elementor: it
     resolves against the card, and an Elementor card is routinely far larger
     than the image inside it (measured live: card 1405x526 vs image 900x506,
     with a wrapper container in between), so the labels aligned to the card
     rather than the artwork. Elementor's own container width also overrode
     the stretch. Leave the geometry to the script. */
  position: absolute;
  z-index: 2;

  /* REQUIRED, not incidental. placeContent() writes the image's exact width
     and height; with the default content-box the padding below is added
     OUTSIDE that, and the overlay ends up one padding wider and taller than
     the artwork it is supposed to sit on. */
  box-sizing: border-box;

  /* Top group pinned up, bottom group pinned down, matching the reference.
     With a single child it simply sits at the top — add the bottom group when
     you want the split. */
  display: flex;
  flex-direction: column;
  justify-content: space-between;

  padding: clamp(16px, 2.2vw, 34px);
  /* Nothing here should stretch full width and swallow clicks across the
     whole card; let each group size to its own content. */
  align-items: flex-start;

  /* The entrance scales this overlay in lockstep with the WebGL mesh, and a
     mesh scales about its centre. Any other origin and the labels would
     drift across the artwork during the reveal instead of growing with it. */
  transform-origin: center center;
}

/* CORNER RADIUS — deliberately NOT set here.

   The card image keeps whatever radius Elementor gave it, and the SHADER
   reads that computed value and clips each plane with a signed-distance
   field. CSS cannot do this job: the canvas spans the whole section, so a
   radius on it would round the section rather than each card, and the canvas
   is not a child of any card, so no amount of overflow:hidden will clip it.

   An earlier revision set `border-radius: inherit` on the image here. That
   is worse than doing nothing — it makes the image inherit the CARD's radius
   (usually none), overriding the value Elementor set directly on the image,
   which is precisely the number the shader needs to read.

   Consequence worth knowing: set the radius on the IMAGE or its immediate
   wrapper in Elementor. A radius set further up the tree is not read. */

/* ==========================================================================
   BRAND ICON — bottom-right, on hover
   --------------------------------------------------------------------------
   The script injects this into .dvl-work-item__content, which placeContent()
   has already pinned to the image's exact box — so `bottom/right` here resolve
   against the artwork, never against the card's column padding.

   Absolute, so it sits outside the overlay's flex column and cannot disturb
   the top/bottom label groups.

   Revealed by `is-hot`, the same class the lens uses: the icon therefore
   appears exactly when the pointer is over the IMAGE, not merely somewhere
   over the card.
   ========================================================================== */
.dvl-work-item__icon {
  position: absolute;
  right: clamp(16px, 2.2vw, 34px);
  bottom: clamp(16px, 2.2vw, 34px);

  display: flex;
  align-items: center;
  justify-content: center;

  color: #f2f2f2;                /* the SVGs use fill="currentColor" */
  pointer-events: none;

  opacity: 0;
  transform: translateY(10px);
  transition: opacity .34s ease, transform .46s cubic-bezier(.22, .61, .36, 1);
}

/* Height only, width auto: the two icons have different aspect ratios
   (webflow 45x29, wordpress 47x47) and each keeps its own via its viewBox.
   Forcing a square box would squash the webflow mark. */
.dvl-work-item__icon svg {
  display: block;
  height: clamp(22px, 2.4vw, 34px);
  width: auto;
}

.dvl-work-item.is-hot .dvl-work-item__icon {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .dvl-work-item__icon {
    transition: opacity .2s ease;
    transform: none;
  }
}

/* The two label groups. Neither is required — use one, both, or neither. */
.dvl-work-item__top,
.dvl-work-item__bottom {
  max-width: min(46ch, 78%);
}

/* Push the bottom group down even when there is no top group. */
.dvl-work-item__bottom {
  margin-top: auto;
}

/* ==========================================================================
   ONE GAP BETWEEN DESCRIPTION AND TAGS, ON EVERY CARD
   --------------------------------------------------------------------------
   Measured on the live page, the space under the description differed by
   card:

     Div 01   row-gap  5px
     Div 02   row-gap 20px
     Div 03   row-gap  5px
     Div 04   row-gap 20px

   Not a layout consequence — nothing was stretching. justify-content
   computed to `normal` on all four and the groups are content-height, so
   image height never entered into it. Two of the four widgets were simply
   given a different gap in the editor, and the four cards had drifted apart
   one edit at a time.

   Forcing it here rather than in Elementor because four per-element values
   are four chances to drift again; this is one number for all four, and it
   holds for any card added later.

   16px is the requested value, exposed as a custom property so it can be
   retuned in one place once the HOME 5 metadata tokens are pulled — the
   Figma cap meant this one is a specified number, not a measured one. */
.dvl-work-item__bottom {
  row-gap: var(--dvl-work-meta-gap, 16px) !important;
}

/* ==========================================================================
   "EXPLORE ALL DIVS" — bracket hover
   --------------------------------------------------------------------------
   Add the class `dvl-explore` to the widget in Elementor. Works on a Heading,
   a Text Editor or a Button: the three selectors below target each widget's
   own text element, and only ONE of them can exist inside a given widget, so
   the brackets are never doubled.

   The gutters are reserved permanently via padding, and only opacity and
   transform animate. Adding margin on hover instead would reflow the label
   and make it jump sideways — the one thing this effect must not do.
   ========================================================================== */
.dvl-explore {
  text-align: center;
}

.dvl-explore .elementor-heading-title,
.dvl-explore .elementor-button-text,
.dvl-explore p {
  display: inline-block;
  position: relative;
  /* room for the brackets, held whether they are shown or not */
  padding: 0 1.6em;
  cursor: pointer;

  /* ---- THE RESTING COLOUR ----------------------------------------------
     The label is quiet until the pointer arrives, then it resolves to full
     ink at the same moment the brackets close in. In the reference the two
     states are a light warm grey and near-black; measured live the label
     was a single flat rgb(67, 62, 52) in both.

     !important is required, not stylistic. Elementor writes

       .elementor-221 .elementor-element.elementor-element-52b5b96
       .elementor-button { color: var(--e-global-color-4a37668) }

     which is (0,3,0) and beats this selector's (0,2,0). Without the flag
     the declaration is simply discarded and nothing changes.

     Both colours are custom properties defaulting to the site tokens, so
     the pair can be retuned from one place once the HOME 5 type tokens are
     pulled — these two values are the estimate in this block. */
  color: var(--dvl-explore-rest, var(--logo-light, #9d988f)) !important;
  transition: color .28s ease;
}

/* :focus-within alongside :hover, matching the bracket rules below — a
   keyboard user tabbing to the link gets the same resolved state. */
.dvl-explore:hover .elementor-heading-title,
.dvl-explore:hover .elementor-button-text,
.dvl-explore:hover p,
.dvl-explore:focus-within .elementor-heading-title,
.dvl-explore:focus-within .elementor-button-text,
.dvl-explore:focus-within p {
  color: var(--dvl-explore-hover, var(--divlab-font-dark, #3a301e)) !important;
}

/* The brackets take the label's colour by inheritance, so they arrive
   already at the hover ink — there is no second declaration to keep in
   step, and no frame where a dark label carries pale brackets. */

.dvl-explore .elementor-heading-title::before,
.dvl-explore .elementor-button-text::before,
.dvl-explore p::before,
.dvl-explore .elementor-heading-title::after,
.dvl-explore .elementor-button-text::after,
.dvl-explore p::after {
  position: absolute;
  top: 0;
  opacity: 0;
  /* Distinct easings: the brackets ease out as they arrive, and the fade is
     slightly faster than the travel so they resolve rather than smear. */
  transition: opacity .28s ease, transform .42s cubic-bezier(.22, .61, .36, 1);
  pointer-events: none;
}

.dvl-explore .elementor-heading-title::before,
.dvl-explore .elementor-button-text::before,
.dvl-explore p::before {
  content: '<';
  left: 0;
  transform: translateX(12px);
}

.dvl-explore .elementor-heading-title::after,
.dvl-explore .elementor-button-text::after,
.dvl-explore p::after {
  content: '>';
  right: 0;
  transform: translateX(-12px);
}

/* :focus-within covers keyboard users tabbing to the link inside the widget —
   the effect should not be mouse-only. */
.dvl-explore:hover .elementor-heading-title::before,
.dvl-explore:hover .elementor-button-text::before,
.dvl-explore:hover p::before,
.dvl-explore:hover .elementor-heading-title::after,
.dvl-explore:hover .elementor-button-text::after,
.dvl-explore:hover p::after,
.dvl-explore:focus-within .elementor-heading-title::before,
.dvl-explore:focus-within .elementor-button-text::before,
.dvl-explore:focus-within p::before,
.dvl-explore:focus-within .elementor-heading-title::after,
.dvl-explore:focus-within .elementor-button-text::after,
.dvl-explore:focus-within p::after {
  opacity: 1;
  transform: translateX(0);
}

@media (prefers-reduced-motion: reduce) {
  .dvl-explore .elementor-heading-title::before,
  .dvl-explore .elementor-button-text::before,
  .dvl-explore p::before,
  .dvl-explore .elementor-heading-title::after,
  .dvl-explore .elementor-button-text::after,
  .dvl-explore p::after {
    transition: opacity .2s ease;
    transform: none;
  }
}

@media (hover: none), (pointer: coarse), (max-width: 1400px) {
  .dvl-works--live .dvl-work-item img,
  .dvl-works--mobile-flow .dvl-work-item img {
    visibility: visible !important;
  }
  .dvl-works__canvas,
  .dvl-works--mobile-flow .dvl-works__canvas {
    display: none !important;
  }

  /* ================================================================
     THE INNER GLOW, WITHOUT THE SHADER
     ----------------------------------------------------------------
     The white wash down the left of every card is drawn by the works
     fragment shader, from CONFIG.innerShadow in dvl-works.js:

         offsetX 356   offsetY 4   blur 250   spread 0
         color #ffffff   opacity 0.30

     — an inset shadow pushed RIGHT, so the glow it opens up sits on
     the left. The rule immediately above is why touch never sees it:
     the canvas is display:none here, so the shader never runs and the
     plain <img> is what is on screen.

     The shader's own comment says a CSS shadow could not be used
     because "once the canvas goes live the DOM <img> is
     visibility:hidden". That is a statement about DESKTOP. Here the
     canvas is off and the <img> is the thing being looked at, so the
     same shadow can simply be drawn in CSS — same geometry, same
     colour, no second renderer.

     ON ::after, NOT ON THE IMAGE. `box-shadow: inset` on a replaced
     element paints UNDER the replaced content, so putting it on the
     <img> would hide it behind the photograph. The pseudo-element is
     an ordinary box stacked over the image, which is the standard way
     round this and the only one that works for <img>.

     The widget wrapper is already position:relative and measures the
     same box as the image to the pixel on all four cards (verified
     live at 375px: img 375x400, wrapper 375x400), so `inset: 0` lands
     exactly on the artwork with nothing to keep in sync. */
  /* Kill all container backgrounds, borders, and shadows behind artwork on touch */
  .dvl-work-item,
  .dvl-work-item *:has(> img),
  .dvl-work-item .elementor-widget-image,
  .dvl-work-item .elementor-widget-container,
  .dvl-work-item .elementor-image,
  .dvl-work-item a:has(> img) {
    background: transparent !important;
    background-color: transparent !important;
    border: none !important;
    box-shadow: none !important;
    outline: none !important;
  }

  /* Clip artwork wrapper to clean 16px rounded corners */
  .dvl-work-item .elementor-widget-image,
  .dvl-work-item .elementor-widget-container,
  .dvl-work-item .elementor-image,
  .dvl-work-item *:has(> img) {
    position: relative;
    border-radius: 16px !important;
    overflow: hidden !important;
    background: transparent !important;
  }

  .dvl-work-item img {
    border-radius: 16px !important;
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
  }

  /* White halo & inner shadow on the artwork across touch/responsive breakpoints */
  .dvl-work-item .elementor-widget-image::after {
    content: '' !important;
    position: absolute !important;
    inset: 0 !important;
    pointer-events: none !important;
    border-radius: 16px !important;
    display: block !important;
    z-index: 2 !important;
    box-shadow: inset
      var(--dvl-work-glow-x, 356px)
      var(--dvl-work-glow-y, 4px)
      var(--dvl-work-glow-blur, 250px)
      0
      rgba(255, 255, 255, var(--dvl-work-glow-alpha, 0.30)) !important;
  }

  @media (max-width: 767px) {
    .dvl-work-item .elementor-widget-image::after {
      --dvl-work-glow-x: 51.7vw;
      --dvl-work-glow-y: 0.6vw;
      --dvl-work-glow-blur: 36.3vw;
    }
  }

  @media (max-width: 1400px) and (min-width: 768px),
         (hover: none) and (min-width: 768px),
         (pointer: coarse) and (min-width: 768px) {
    .dvl-work-item .elementor-widget-image::after {
      --dvl-work-glow-x: clamp(240px, 35vw, 356px);
      --dvl-work-glow-y: 4px;
      --dvl-work-glow-blur: clamp(160px, 25vw, 250px);
      --dvl-work-glow-alpha: 0.30;
    }
  }

  @media (max-height: 540px) and (orientation: landscape) {
    .dvl-work-item .elementor-widget-image::after {
      --dvl-work-glow-x: clamp(180px, 45vh, 280px);
      --dvl-work-glow-y: 4px;
      --dvl-work-glow-blur: clamp(120px, 35vh, 200px);
      --dvl-work-glow-alpha: 0.30;
    }
  }

  /* ================================================================
     THE OVERLAY BECOMES A CAPTION AGAIN
     ----------------------------------------------------------------
     .dvl-work-item__content is position:absolute so placeContent() can
     pin it to the artwork's exact box. On touch that script never runs
     — init() bails on matchMedia('(hover: none)') before it builds
     anything — so the rule is left standing with NO box to fill.

     An absolutely positioned block with no width shrink-wraps, and one
     with no height grows as tall as its text. Measured on the live page
     at 390px: every caption came out 230px wide and 550px tall over a
     card only 130-230px tall, so each one overflowed 300-400px straight
     down through the cards beneath it. Four cards deep that is the
     column of interleaved, unreadable text in the recording — "Div 02"
     printed through "<Possibility>" printed through a description
     belonging to the card above.

     Nothing about pinning a label over artwork makes sense on a phone
     anyway: the image is 390px wide and the description needs more room
     than the image has. So the caption returns to normal flow and sits
     UNDER its image, which is what a card is.

     The !important flags are not decoration. placeContent() writes
     left/top/width/height as INLINE styles, and a visitor who rotates a
     tablet from landscape into this breakpoint arrives carrying a full
     set of them; a plain declaration would lose to every one. */
  .dvl-work-item__content {
    position: static;
    width: auto !important;
    height: auto !important;
    max-width: none !important;
    left: auto !important;
    top: auto !important;
    /* Only the top gutter is wanted now — the sides belong to the
       section's own padding, and the caption is no longer inset into
       artwork that would need them. */
    padding: 16px 0 0 !important;
    /* The entrance tween scales this in lockstep with the WebGL mesh.
       There is no mesh here. */
    transform: none !important;
  }

  /* Both label groups were held to 78% so they could not run across the
     full width of the artwork. Below the artwork, full width is exactly
     what they want. */
  .dvl-work-item__top,
  .dvl-work-item__bottom {
    max-width: none;
  }

  /* margin-top: auto pushed this to the bottom of a fixed-height
     overlay. In flow it would collapse against the group above. */
  .dvl-work-item__bottom {
    margin-top: 10px;
  }

  /* A hover affordance with no hover to reveal it. It is also absolutely
     positioned against a box that no longer exists. */
  .dvl-work-item__icon {
    display: none;
  }

  /* The cards used to be exactly as tall as their artwork, because the
     text was lifted out of flow. Now that it is back in, they need
     separating from each other. */
  .dvl-work-item {
    margin-bottom: 44px;
  }
  .dvl-work-item[data-dvl-card="4"],
  .dvl-work-item:last-of-type {
    margin-bottom: 0 !important;
  }
}

/* ==========================================================================
   THE EDITORIAL STAGGER DOES NOT SURVIVE A PHONE
   --------------------------------------------------------------------------
   A WIDTH query, not a hover one — unlike the block above. The stagger is a
   layout that runs out of room, and it runs out of room on a narrow screen
   whether or not that screen has a pointer.

   In Elementor the middle two cards carry `margin-left: 74px`, offsetting
   them from the outer two. On a wide screen that is the asymmetric,
   editorial rhythm the section is built around. On a 390px screen it is
   simply 74px the layout does not have.

   WHY IT PUSHED *EVERY* CARD RIGHT, INCLUDING THE ONES WITH NO MARGIN.
   The cards are flex items in a column container with `align-self: center`,
   so each is centred on the cross axis — horizontally. The margin does not
   just move its own card: it widens that card's outer box to 444px, which
   becomes the widest thing on the flex line, and every OTHER card is then
   centred against 444 instead of the container's 370. Measured at 390px:

       card 0   left  47   right 417    27px past the viewport
       card 1   left  84   right 454    64px past the viewport
       card 2   left  84   right 454    64px past the viewport
       card 3   left  47   right 417    27px past the viewport

   Cards 0 and 3 have `margin-left: 0` and were still displaced by 37px —
   exactly half the 74px that cards 1 and 2 added to the line. That is why
   the whole section looked shifted rather than just two rows of it, and why
   the descriptions were clipped at the right edge.

   Neutralising the margins collapses the line back to the container's own
   content box and all four land flush: left 10, right 380, symmetric
   gutters, document scrollWidth back to 390 with no horizontal overflow.

   `!important` because Elementor writes these margins as per-element rules
   (`.elementor-NNN .elementor-element.elementor-element-xxxxx`), which
   outrank a plain class selector. `width: 100%` rather than leaving the
   authored 370px so the cards also fit a 360px phone, where a fixed 370
   would overflow again on its own. */
@media (max-width: 767px), ((max-height: 540px) and (orientation: landscape)) {
  .dvl-work-item {
    margin-left: auto !important;
    margin-right: auto !important;
    width: 100% !important;
    max-width: 100%;
  }
}

/* ==========================================================================
   TABLET & MOBILE LANDSCAPE — CLEAN CARD ARTWORK CORNERS (NO BACKGROUND ARTIFACT)
   --------------------------------------------------------------------------
   In tablet portrait, tablet landscape, and mobile landscape:
   Kill any container backgrounds, borders, or box-shadows behind the artwork.
   Enforce clean 16px corner clipping with overflow: hidden on the wrappers.
   ========================================================================== */
@media (max-width: 1400px) and (min-width: 768px),
       (hover: none) and (min-width: 768px),
       (pointer: coarse) and (min-width: 768px),
       ((max-height: 540px) and (orientation: landscape)) {
  .dvl-work-item,
  .dvl-work-item *:has(> img),
  .dvl-work-item .elementor-widget-image,
  .dvl-work-item .elementor-widget-container,
  .dvl-work-item .elementor-image,
  .dvl-work-item a:has(> img) {
    background: transparent !important;
    background-color: transparent !important;
    border: none !important;
    box-shadow: none !important;
    outline: none !important;
  }

  .dvl-work-item .elementor-widget-image,
  .dvl-work-item .elementor-widget-container,
  .dvl-work-item .elementor-image,
  .dvl-work-item *:has(> img) {
    border-radius: 16px !important;
    overflow: hidden !important;
    background: transparent !important;
  }

  .dvl-work-item img {
    border-radius: 16px !important;
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
  }

  .dvl-work-item .elementor-widget-image::after {
    content: '' !important;
    position: absolute !important;
    inset: 0 !important;
    pointer-events: none !important;
    border-radius: 16px !important;
    display: block !important;
    z-index: 2 !important;
    box-shadow: inset
      var(--dvl-work-glow-x, 356px)
      var(--dvl-work-glow-y, 4px)
      var(--dvl-work-glow-blur, 250px)
      0
      rgba(255, 255, 255, var(--dvl-work-glow-alpha, 0.30)) !important;
  }
}

/* ==========================================================================
   PHONE — MEDIA BLEEDS EDGE TO EDGE, TYPE KEEPS THE 24px GUTTER
   --------------------------------------------------------------------------
   Two different measurements in the same card: the artwork is full viewport
   width with no margin at all, and every line of type sits exactly 24px from
   the screen edge — the gutter the rest of the site standardised on.

   WHY `(hover: none)` AS WELL AS THE WIDTH. Not belt-and-braces; it prevents
   a real regression. Below 768px on a DESKTOP window — someone dragging the
   browser narrow — init() does NOT bail, so WebGL runs and placeContent()
   pins the caption to the artwork with INLINE left/top/width/height. The
   rules below carry !important, which beats an inline declaration, so a
   width-only query would tear that overlay apart on a narrow desktop window
   while leaving the canvas drawing underneath it.

   Gating on hover:none matches the rest of the file's contract: hover:none
   means no WebGL, which means no overlay to protect, which means the caption
   is already a static block in flow and is ours to move. A phone matches
   both halves; a narrow desktop window matches neither.

   ---- THE FULL-BLEED MEASUREMENT --------------------------------------
   `width: 100vw; margin-left: calc(50% - 50vw)`.

   The 50% resolves against the card, and the card is 100% of the section
   container, so the card's width is the viewport minus the container's two
   paddings. That makes the margin

       (viewport - 2p)/2 - viewport/2  =  -p

   — exactly the container's own left padding, whatever it happens to be,
   pulled back off. No number from Elementor is hard-coded here and changing
   the section padding cannot break the bleed.

   It also cannot create a horizontal scrollbar: the element ends up exactly
   100vw wide starting at x = 0, so scrollWidth stays at the viewport.

   Applied to the image WRAPPER, never to both the wrapper and the <img>, or
   the negative margin would be taken twice and the artwork would hang off
   the left edge by a full container padding.

   ---- AND THE TYPE ------------------------------------------------------
   The caption is bled the same way and then given a real 24px padding. Doing
   it in one move rather than trusting the container's padding is what makes
   the gutter exact: the type is 24px from the SCREEN, not 24px from whatever
   Elementor currently has on the section.
   ========================================================================== */
@media (max-width: 767px), ((max-height: 540px) and (orientation: landscape)) {
  .dvl-work-item *:has(> img) {
    width: 100% !important;
    max-width: 100% !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
  }

  .dvl-work-item img {
    width: auto !important;
    height: auto !important;
    max-width: 100% !important;
    aspect-ratio: auto !important;
    object-fit: contain;
    object-position: center;
    border-radius: 16px !important;
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
  }

  /* ---- FALLBACK: ONE CAPTION BLOCK UNDER THE MEDIA ---------------------
     What the card looks like if dvl-works.js never ran — no WebGL, a script
     error, JS disabled. All four metadata lines stay in one block below the
     artwork, bled and gutted the same way. Not as designed, but correct and
     readable, which is the whole point of keeping a fallback.

     The three-part flow below REPLACES this, and only once the script has
     actually moved the slug (see .dvl-works--mobile-flow). */
  .dvl-work-item__content {
    width: 100vw !important;
    max-width: 100vw !important;
    margin-left: calc(50% - 50vw) !important;
    margin-right: 0 !important;
    padding: 16px 24px 0 !important;
  }

  /* The gutter has to be 24px to the GLYPHS, not to a box that then insets
     them further. Both label groups are Elementor `e-con-full` containers
     and carry its default 10px padding, which measured on the live page put
     every line at 34px from the screen edge — 24 from the caption plus 10
     from the group inside it. Zeroed here so the caption's 24px is the only
     horizontal measurement in the stack.

     Horizontal only. The vertical padding is real spacing between the two
     groups and is left exactly as Elementor set it. */
  .dvl-work-item__top,
  .dvl-work-item__bottom {
    padding-left: 0 !important;
    padding-right: 0 !important;
  }
}

/* ==========================================================================
   PHONE — THE THREE-PART CARD, MATCHING home-mobile-8
   --------------------------------------------------------------------------
   The phone card is not the desktop card with the overlay dropped
   underneath. It is three distinct bands:

       Div 01            above the artwork,  24px gutter, on the page colour
       <Inflow>          ON the artwork,     24px in from its top-left
       description       below the artwork,  24px gutter
       Design,Develop    below that

   ---- WHY THIS NEEDS BOTH CSS AND A DOM MOVE ---------------------------
   In the markup Elementor produces, the artwork and the caption are
   siblings, and BOTH metadata groups live inside the caption:

       .dvl-work-item
         ├ <image widget>
         └ .dvl-work-item__content
              ├ .dvl-work-item__top      Div 01 , <Inflow>
              └ .dvl-work-item__bottom   description , Design,Develop

   Getting the artwork BETWEEN __top and __bottom is a reordering problem,
   and `order` only sorts siblings — __top and __bottom are nested one level
   too deep. `display: contents` on __content solves exactly that: the box
   disappears, its children are promoted into the card's own flex line, and
   all three bands become orderable siblings.

   The slug cannot be solved that way. It has to sit ON the artwork, which
   means absolute positioning against the image's box — and its top offset
   would depend on the height of "Div 01" above it, a number CSS has no way
   to reference. So dvl-works.js physically moves the slug into the image's
   wrapper, where `top: 24px` means 24px from the artwork whatever is
   stacked above. That is the one thing here that genuinely cannot be done
   in a stylesheet.

   ---- WHY THE GUTTERS MOVE ONTO THE GROUPS -----------------------------
   `display: contents` removes __content's box, and with it the 24px padding
   that was holding the gutter. The bleed-and-inset therefore transfers to
   __top and __bottom individually. Same calc, same reasoning, applied one
   level down.

   ---- THE CLASS GATE ---------------------------------------------------
   Every rule is scoped to .dvl-works--mobile-flow, which the script adds
   only AFTER the slug has been moved. Without it none of this applies and
   the fallback above stands — so a script that fails halfway can never
   leave a card half-reordered with its slug still in the caption.
   ========================================================================== */
@media (max-width: 1400px), (hover: none), (pointer: coarse), ((max-height: 540px) and (orientation: landscape)) {
  /* Three-band responsive card layout:
     1. .dvl-work-item__index-bar (Div 01) at top
     2. Artwork image (clean, transparent background, no border)
     3. .dvl-work-item__content (Project name <Inflow>, description, tags) below artwork */
  .dvl-works--mobile-flow .dvl-work-item,
  .dvl-works--mobile-flow .dvl-work-item[data-dvl-card] {
    display: flex !important;
    flex-direction: column !important;
    row-gap: 0 !important;
    width: 100% !important;
    max-width: 100% !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
    align-self: stretch !important;
    margin-bottom: clamp(48px, 9vh, 80px) !important;
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
  }

  .dvl-works--mobile-flow .dvl-work-item__index-bar {
    width: 100% !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
    padding-bottom: 10px !important;
    box-sizing: border-box !important;
  }

  .dvl-works--mobile-flow .dvl-work-item__index-bar .elementor-heading-title,
  .dvl-works--mobile-flow .dvl-work-item__index-bar p {
    font-family: 'IBM_Plex_Mono', ui-monospace, monospace !important;
    font-size: 14px !important;
    font-weight: 400 !important;
    letter-spacing: 0 !important;
    color: var(--divlab-font-dark, #3a301e) !important;
    margin: 0 !important;
  }

  /* Artwork container: kill any white container background / border from Elementor */
  .dvl-works--mobile-flow .dvl-work-item *:has(> img),
  .dvl-works--mobile-flow .dvl-work-item .elementor-widget-image {
    width: 100% !important;
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
    margin: 0 !important;
  }

  .dvl-works--mobile-flow .dvl-work-item img {
    border-radius: 16px !important;
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
  }

  /* Info list below artwork */
  .dvl-works--mobile-flow .dvl-work-item__content {
    position: static !important;
    transform: none !important;
    width: 100% !important;
    max-width: 100% !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
    padding-top: 12px !important; /* Distance from bottom of artwork */
    box-sizing: border-box !important;
    display: flex !important;
    flex-direction: column !important;
    row-gap: 5px !important;      /* Tightened distance between name & description */
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
  }

  .dvl-works--mobile-flow .dvl-work-item__top,
  .dvl-works--mobile-flow .dvl-work-item__bottom {
    padding-left: 0 !important;
    padding-right: 0 !important;
    margin: 0 !important;
  }

  .dvl-works--mobile-flow .dvl-work-item__top {
    padding-bottom: 0 !important;
    margin-bottom: 0 !important;
  }

  .dvl-works--mobile-flow .dvl-work-item__top .elementor-heading-title,
  .dvl-works--mobile-flow .dvl-work-item__top p {
    font-family: 'IBM_Plex_Mono', ui-monospace, monospace !important;
    font-size: 15px !important;
    color: var(--divlab-font-dark, #3a301e) !important;
    margin: 0 !important;
  }

  .dvl-works--mobile-flow .dvl-work-item__bottom {
    display: flex !important;
    flex-direction: column !important;
    row-gap: 6px !important;      /* Tightened distance between description & category */
    margin-top: 0 !important;
    padding-top: 0 !important;
  }

  .dvl-works--mobile-flow .dvl-work-item__content p,
  .dvl-works--mobile-flow .dvl-work-item__content .elementor-heading-title,
  .dvl-works--mobile-flow .dvl-work-item__top *,
  .dvl-works--mobile-flow .dvl-work-item__bottom * {
    margin-top: 0 !important;
    margin-bottom: 0 !important;
  }

  /* ==========================================================================
     CARD 4 & "EXPLORE ALL DIVS" VERTICAL RHYTHM (ALL NON-DESKTOP BREAKPOINTS)
     --------------------------------------------------------------------------
     1. Last card (Card 4) carries margin-bottom: 0 so it hands off tightly
        to the Explore CTA without an inflated card gap.
     2. Explore All Divs sits close to Card 4 (~28px-32px), making it immediately
        read as belonging to Selected Divs.
     3. The gap between Explore All Divs and Agency Services is slightly reduced
        (~56px-64px total), but remains distinctly larger than the gap above it,
        preserving clear visual hierarchy between the two sections.
     ========================================================================== */
  .dvl-works--mobile-flow .dvl-work-item[data-dvl-card="4"],
  .dvl-works--mobile-flow .dvl-work-item:last-of-type,
  .dvl-works .dvl-work-item[data-dvl-card="4"],
  .dvl-works .dvl-work-item:last-of-type,
  .dvl-work-item[data-dvl-card="4"],
  .dvl-work-item:last-of-type {
    margin-bottom: 0 !important;
  }

  .dvl-explore,
  .dvl-works .dvl-explore,
  #dvl-works .dvl-explore,
  #dvl-works .elementor-widget.dvl-explore {
    margin-top: clamp(24px, 3.8vh, 32px) !important;
    margin-bottom: clamp(16px, 2.5vh, 22px) !important;
    padding-top: 0 !important;
    padding-bottom: 0 !important;
  }

  .dvl-explore .elementor-widget-container {
    margin-top: 0 !important;
    margin-bottom: 0 !important;
    padding-top: 0 !important;
    padding-bottom: 0 !important;
  }

  #dvl-works > .e-con:has(.dvl-explore),
  #dvl-works > .elementor-element:has(.dvl-explore) {
    margin-top: 0 !important;
    margin-bottom: 0 !important;
    padding-top: 0 !important;
    padding-bottom: 0 !important;
  }

  #dvl-works {
    padding-bottom: 0 !important;
  }
}

/* ==========================================================================
   SELECTED DIVS SECTION GUTTER SYNCHRONIZATION WITH HEADER & FOOTER
   --------------------------------------------------------------------------
   Guarantees that #dvl-works content aligns precisely with the site-wide
   80px grid on Tablet Portrait, Tablet Landscape, and Mobile Landscape.
   ========================================================================== */
@media (min-width: 768px) and (max-width: 1400px) and (min-height: 541px),
       (hover: none) and (min-width: 768px) and (min-height: 541px),
       (pointer: coarse) and (min-width: 768px) and (min-height: 541px) {
  #dvl-works {
    padding-top: clamp(80px, 16vh, 140px) !important;
    padding-left: 80px !important;
    padding-right: 80px !important;
    box-sizing: border-box !important;
  }
}

@media (max-height: 540px) and (orientation: landscape) {
  #dvl-works {
    padding-top: clamp(60px, 25vh, 120px) !important;
    padding-left: calc(env(safe-area-inset-left, 0px) + 24px) !important;
    padding-right: calc(env(safe-area-inset-right, 0px) + 24px) !important;
    box-sizing: border-box !important;
  }

  .dvl-works--mobile-flow .dvl-work-item,
  .dvl-works--mobile-flow .dvl-work-item[data-dvl-card] {
    max-width: min(85vw, 560px) !important;
    margin-left: 0 !important;
    margin-right: auto !important;
    align-self: flex-start !important;
    margin-bottom: clamp(44px, 12vh, 64px) !important;
  }

  .dvl-works--mobile-flow .dvl-work-item *:has(> img),
  .dvl-works--mobile-flow .dvl-work-item .elementor-widget-image {
    width: auto !important;
    max-width: 100% !important;
    display: flex !important;
    justify-content: flex-start !important;
    align-items: flex-start !important;
    margin-left: 0 !important;
    margin-right: auto !important;
  }

  .dvl-works--mobile-flow .dvl-work-item img {
    max-height: clamp(210px, 62vh, 290px) !important;
    width: auto !important;
    max-width: 100% !important;
    height: auto !important;
    object-fit: contain !important;
    aspect-ratio: auto !important;
    display: block !important;
    margin-left: 0 !important;
    margin-right: auto !important;
  }

  .dvl-works--mobile-flow .dvl-work-item__index-bar {
    padding-left: 0 !important;
    padding-right: 0 !important;
    text-align: left !important;
  }

  .dvl-works--mobile-flow .dvl-work-item__content {
    padding-left: 0 !important;
    padding-right: 0 !important;
    text-align: left !important;
  }
}

@media (max-width: 767px) and (orientation: portrait) {
  #dvl-works {
    padding-top: clamp(80px, 18vh, 140px) !important;
    padding-left: 24px !important;
    padding-right: 24px !important;
    box-sizing: border-box !important;
  }

  .dvl-works--mobile-flow .dvl-work-item,
  .dvl-works--mobile-flow .dvl-work-item[data-dvl-card] {
    max-width: min(88vw, 340px) !important;
    margin-left: auto !important;
    margin-right: auto !important;
    align-self: center !important;
    margin-bottom: clamp(40px, 7vh, 64px) !important;
  }

  .dvl-works--mobile-flow .dvl-work-item *:has(> img),
  .dvl-works--mobile-flow .dvl-work-item .elementor-widget-image {
    width: 100% !important;
    max-width: 100% !important;
    display: flex !important;
    justify-content: center !important;
    align-items: center !important;
    margin: 0 auto !important;
  }

  .dvl-works--mobile-flow .dvl-work-item img {
    width: 100% !important;
    max-width: 100% !important;
    height: auto !important;
    max-height: 42vh !important;
    aspect-ratio: auto !important;
    object-fit: cover !important;
    border-radius: 16px !important;
    display: block !important;
    margin: 0 auto !important;
  }

  .dvl-works--mobile-flow .dvl-work-item__index-bar {
    padding-left: 0 !important;
    padding-right: 0 !important;
  }

  .dvl-works--mobile-flow .dvl-work-item__content {
    padding-left: 0 !important;
    padding-right: 0 !important;
  }
}

/* ==========================================================================
   PHONE — THE METADATA RISES INTO VIEW
   --------------------------------------------------------------------------
   Scope is deliberately narrow: the four PER-PROJECT lines only.

     Div 01              .dvl-work-item__top    > child 1
     <Inflow>            .dvl-work-item__top    > child 2
     description         .dvl-work-item__bottom > child 1
     Design,Develop      .dvl-work-item__bottom > child 2

   The section title ("Selected Divs" and <DIV-BOX>) is NOT in this set and
   is not touched — it scrolls as ordinary static header content.

   dvl-works.js wraps each of those four in a .dvl-reveal-clip span and adds
   .dvl-reveal-in to the GROUP when it enters view. Two groups per card
   rather than one trigger per card: a full-bleed card is most of a phone
   screen tall, so a single trigger on the card would start the description
   animating while it was still hundreds of pixels below the fold.

   ---- WHY IntersectionObserver AND CSS, NOT ScrollTrigger ----------------
   This is a one-shot reveal on entry, which is exactly what IO does, and it
   costs no scroll handler at all. ScrollTrigger would also have to be
   refreshed in step with the pins dvl-stage.js builds on the same page —
   the precise coupling that put this module's entrance triggers 3700px out
   of position once already (see whenSettled() in dvl-works.js). There is no
   reason to re-enter that relationship for a four-line fade.

   ---- WHY 110% AND NOT 100% ---------------------------------------------
   translateY(100%) clears the element's own box, but a descender or a
   line-height larger than the glyphs can still paint a sliver above the
   clip's bottom edge on the first frame. 110% is hidden by the same
   overflow, so the extra costs nothing and removes the flicker.

   The clip itself is display:block at ALL widths. The wrapper is inserted
   once, and a <span> left inline around a block-level Elementor div is
   invalid flow that some browsers repair by splitting the box — so it is
   given a block display unconditionally, and only the overflow and the
   transform are held inside the media query.
   ========================================================================== */
/* FLEX, NOT BLOCK, AND THIS IS THE LOAD-BEARING DECLARATION IN THE REVEAL.

   translateY(110%) is a percentage of the LINE's own height, which only
   conceals the line if the clip is the same height as it. Measured on the
   live page it is not: the clip came out 35.4px around a 21px line, and the
   hidden state leaked 12.3px of glyph — the top of every word sat visible
   above the fold of its own mask.

   Probed six ways (flow-root, align-self, flex:0 0 auto, line-height:0) the
   clip does not size to its content and __top has no intrinsic height of its
   own to explain it. Rather than keep guessing at Elementor's box model, the
   fix is made independent of the cause: `display: flex` stretches the line to
   fill the clip, whatever the clip's height is, so 110% of the line is always
   at least 100% of the clip and the mask always closes.

   Verified: line height goes 21 -> 35.4, matching the clip exactly.

   Safe at every width — clips are only ever created on a phone, since
   buildMobileReveal() bails before wrapping anything otherwise. */
.dvl-reveal-clip {
  display: flex;
}

@media (max-width: 767px), ((max-height: 540px) and (orientation: landscape)) {
  .dvl-reveal-clip {
    overflow: hidden;
  }

  .dvl-reveal-clip > * {
    display: block;
    flex: 1 1 100%;
    transform: translateY(110%) !important;
    transition: transform var(--dvl-reveal-dur, .85s) cubic-bezier(.22, .61, .36, 1) !important;
    transition-delay: var(--dvl-reveal-delay, 0s) !important;
  }

  .dvl-reveal-in > .dvl-reveal-clip > * {
    transform: translateY(0) !important;
  }
}

/* Someone who asked for reduced motion gets the text, immediately, with no
   clip to hide it. dvl-works.js also declines to build the observers at all
   under this setting, so this is the second of two independent guards — the
   type must never be left translated out of a box with nothing coming to
   bring it back. */
@media (prefers-reduced-motion: reduce) {
  .dvl-reveal-clip {
    overflow: visible;
  }
  /* BOTH selectors, and the longer one is not redundant. The rules above now
     carry !important, so the cascade is decided on specificity alone:
     `.dvl-reveal-in > .dvl-reveal-clip > *` is (0,3,0) and would outrank a
     lone `.dvl-reveal-clip > *` at (0,1,0) even from a later block. Matching
     its shape here is what keeps this guard authoritative. */
  .dvl-reveal-clip > *,
  .dvl-reveal-in > .dvl-reveal-clip > * {
    transform: none !important;
    transition: none !important;
  }
}

/* Respect the OS setting. Someone who has asked for reduced motion should not
   get a rippling image under the cursor. */
@media (prefers-reduced-motion: reduce) {
  .dvl-works--live .dvl-work-item img {
    visibility: visible;
  }
  .dvl-works__canvas {
    display: none;
  }
}
