@import url('https://fonts.googleapis.com/css2?family=Inter:wght@200;300;400;500;600;700&display=swap');

/* ==========================================================================
   DIVLAB DIVS — layout and typography for the cylindrical drum showcase
   --------------------------------------------------------------------------
   Scoped entirely to this 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 alongside dvl-works.css and dvl-services.css.

   The module positions nothing from JavaScript except the titles' own
   transforms. Everything below — the full-bleed canvas, the centred type, the
   arrows — is CSS, so the page is already laid out correctly before the module
   runs and does not reflow when it does.
   ========================================================================== */

/* ==========================================================================
   THE SECTION
   --------------------------------------------------------------------------
   Z-INDEX IS NOT OPTIONAL HERE — see the same note in dvl-services.css and
   dvl-footer.css. dvl-stage.js puts ONE fixed, full-viewport canvas directly
   on <body> at z-index: 0, and it is the last element in the DOM. `z-index:
   auto` and `z-index: 0` sit in the same stacking layer, so DOM order breaks
   the tie and that canvas paints straight over any full-bleed section which
   does not claim a layer of its own. This has bitten works, services and the
   footer in turn; it is stated once more rather than rediscovered.
   ========================================================================== */
.dvl-divs {
  /* ======================================================================
     EVERY VISUAL CHOICE IS A VARIABLE, AND THIS IS THE ONLY BLOCK TO EDIT
     ----------------------------------------------------------------------
     Override any of these from Elementor without touching this file: select
     the section, Advanced > Custom CSS, and write

         selector { --dvl-divs-color: #1f1f1f; }

     (or Appearance > Customize > Additional CSS with `.dvl-divs { ... }` if
     Custom CSS is not available on your Elementor licence). Nothing else in
     this stylesheet hardcodes a colour or a size, so a single line there
     changes the whole reel and survives every future update to this file.
     ====================================================================== */

  /* Type. Explicitly set to the site's Inter display stack so it never falls
     back to the browser's default generic serif (Times New Roman) when
     Elementor Canvas or an unstyled template is used. */
  --dvl-divs-font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --dvl-divs-size: clamp(24px, 3.6vw, 46px);
  --dvl-divs-weight: 400;
  --dvl-divs-weight-active: 400;
  --dvl-divs-tracking: 0.005em;
  --dvl-divs-leading: 1.16;

  /* Colour. Dark charcoal, not white — set for photographs that are light in
     the middle. Over a dark image this will disappear; that is what
     --dvl-divs-shadow is for, and the pairing is discussed below. */
  --dvl-divs-color: #ffffff;
  --dvl-divs-arrow-color: var(--dvl-divs-color);

  /* A WHITE halo, under dark type. That pairing looks wrong written down and
     is exactly right in practice, because it is SELF-LIMITING: white glow on a
     light photograph is invisible, and only shows up where the image behind
     the centre belt is actually dark. One value therefore covers a reel whose
     images range from near-black to near-white, with no per-slide handling.

     It is here because it was measured, not assumed. Relative luminance of the
     belt each title sits in, and its WCAG contrast against #2f2f2f:

       Inflow       0.080   1.66   <- fails; the 3:1 floor for large text
       Possibility  0.239   3.69
       Qx           0.414   5.92
       Hope         0.527   7.36

     Two layers rather than one: the tight core does the legibility work, the
     wide one keeps it from reading as an outline. Set this to `none` if every
     image in the reel is light through the middle — the reference has no halo
     at all, and it is the single thing that most makes type look pasted onto
     a photograph. */
  --dvl-divs-shadow: none;

  /* `difference` inverts the type against whatever is behind it, so it is
     legible on a near-black photograph and a near-white one with no halo and
     no per-slide handling. That is why the halo is gone: the two solve the
     same problem, and stacking them just makes the type look muddy.

     WHICH IS ALSO WHY THE COLOUR IS NOW WHITE. `difference` subtracts, so the
     effect is proportional to how bright the ink is: the old #2f2f2f ink
     shifts the backdrop by at most 47/255 and is nearly invisible. White
     inverts fully — black on light images, white on dark ones.

     THE ONE PLACE IT FAILS is mid-grey. White differenced against rgb(128,
     128,128) returns rgb(127,127,127), i.e. the type disappears into its own
     backdrop. Measured per project at the centre belt, as "backdrop -> what
     the type becomes":

       Inflow        dark orange   -> cyan-blue      clearly legible
       Possibility   pale mist     -> dark grey      legible
       Hope          cream         -> dark blue      strongly legible
       Qx            pale blue     -> dark orange    strongly legible

     No slide currently lands in the dead band, but it is the thing to re-check
     if a future project image is flat mid-grey through the middle of frame.
     Setting --dvl-divs-blend to `normal` restores plain ink. */
  --dvl-divs-blend: difference;

  /* Arrows. `gap` is the clear space between the edge of the centred title
     and the arrow, so the pair tracks the title's width rather than sitting
     at the edges of the screen. */
  --dvl-divs-arrow-size: 0.62em;
  --dvl-divs-arrow-weight: 300;
  /* 4.25em, measured off the reference screenshot rather than guessed.
     That shot is 1920 device px wide, but the display it was taken on runs at
     125% scale, so the viewport is 1536 CSS px — at which the title clamp
     settles on its 46px ceiling. Working in CSS px: title 606 wide, gap 196,
     and 196 / 46 = 4.25em. Checking the arithmetic the other way, 4.25em puts
     the arrows at 17% and 83% of the width, which is where they sit in the
     screenshot.

     em, not px or vw, so the gap keeps its proportion to the type when the
     size changes. The arrows still TRACK the title, so a short name like
     "Qx Studio" brings them inward — this is the clear space beside the name,
     not a fixed position on screen. */
  --dvl-divs-arrow-gap: 4.25em;
  --dvl-divs-arrow-opacity: 0.85;

  /* Written by the module every frame: half the width of whatever title is
     currently centred, in px. The arrows are positioned from it. Declared
     here so the first paint is sane before any JS runs. */
  --dvl-divs-title-half: 160px;

  position: relative;
  z-index: 1;

  /* 100svh, with a vh fallback for browsers that predate it. On a phone,
     100vh is the height of the viewport with the address bar RETRACTED, so a
     full-bleed section measured in vh is cropped by the toolbar on load and
     jumps the moment the visitor scrolls. svh is the stable small viewport. */
  height: 100vh;
  height: 100svh;
  min-height: 480px;

  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;

  /* The module consumes the wheel and owns the drag gesture. touch-action:
     none tells the compositor not to start its own scroll or pinch first —
     without it a swipe is claimed by the browser before the first pointermove
     is ever delivered, and the reel simply does not move on a phone. */
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;

  /* Matches the renderer's clear colour, so the split-second before the first
     frame is the same colour as the first frame. */
  background-color: #0d0d0d;

  cursor: grab;
  outline: none;
}

/* The tape follows the hand one-to-one while dragging, so the cursor should
   say so. */
.dvl-divs.is-dragging {
  cursor: grabbing;
}

.dvl-divs:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.65);
  outline-offset: -4px;
}

/* ==== THE NO-WEBGL FALLBACK ===============================================
   If the renderer never starts, dvl-divs.js writes the nearest project's image
   straight onto the section as a background, and every DOM behaviour — the
   reel, the arrows, the links, the keyboard — carries on working. These are
   the properties that make that readable; they are inert while the canvas is
   present, because the canvas covers them.

   WHY AN ID SELECTOR AND !important, WHICH THIS FILE OTHERWISE AVOIDS
   Two rules on the live site set background-image with !important on every
   element, and a plain class (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. An ID (1,0,0)
   outranks both, and !important is required to compete at all since theirs
   carry it. The module's own inline write uses setProperty(..., 'important')
   for exactly the same reason.
   ========================================================================= */
#dvl-divs {
  background-size: cover !important;
  background-position: center !important;
  background-repeat: no-repeat !important;
}

/* ==========================================================================
   THE CANVAS
   ========================================================================== */
.dvl-divs__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 0;

  /* Essential. The wheel, drag and click listeners live on the SECTION and the
     title links sit above. A canvas that swallowed pointer events would make
     every anchor in the reel dead.

     Note there is no border, no outline and no box-shadow here, and nothing
     anywhere else in this file targets the canvas. A 1px border on a
     full-bleed canvas reads exactly like a seam artefact in the render, and
     is impossible to tell apart from one without a screenshot. */
  pointer-events: none;
}

/* ==========================================================================
   THE REEL
   --------------------------------------------------------------------------
   A full-section window with a zero-sized track centred inside it. That track
   is the origin every title is positioned from, so a title at translateY(0)
   is exactly in the middle of the screen and the module's ring arithmetic
   needs no origin offset of its own.
   ========================================================================== */
.dvl-divs__reel {
  position: absolute;
  inset: 0;
  z-index: auto;

  display: flex;
  align-items: center;
  justify-content: center;

  /* The titles overflow this box in both directions by design — the whole
     list is on screen at once. The SECTION clips. */
  /* z-index: auto — see the note below. Do not reintroduce a number here. */
  overflow: visible;
  pointer-events: none;
}

/* ==== WHY NOTHING IN HERE MAY CARRY A Z-INDEX =============================
   mix-blend-mode blends an element with its BACKDROP, and the backdrop stops
   at the nearest ancestor that forms a stacking context. `position` plus any
   z-index other than `auto` forms one.

   This reel used to be `position: absolute; z-index: 2`. That is a stacking
   context, so the titles blended against the reel's own contents — which are
   nothing — and `difference` did exactly nothing on the live page while still
   reporting `mix-blend-mode: difference` in the computed style. Measuring the
   computed property is not a test of blending; only looking at the composited
   pixels is.

   z-index: auto keeps the painting order anyway: positioned elements with
   `auto` and with `0` paint in the same pass, in DOM order, and the module
   inserts the canvas as the FIRST child. So the canvas still paints first and
   everything here still paints over it — the difference is that the titles can
   now see it as their backdrop.
   ========================================================================= */

.dvl-divs__track {
  position: relative;

  /* A zero-sized positioning context, nothing more. Every title is absolutely
     positioned on its centre point and carries its own translate — the track
     itself never moves, so the reel wraps as a ring without a duplicated
     list. Because it has no content box, none of those writes cost a layout. */
  backface-visibility: hidden;
}

/* ==========================================================================
   THE TITLES
   --------------------------------------------------------------------------
   Real anchors. Crawlable, focusable when centred, and only ever transformed.
   The whole list is rendered at once and scrubs continuously past the centre
   line — there is no "previous / active / next" set, because at a scroll
   position of 2.5 there is no single active item and pretending otherwise is
   what made the first build feel like a slideshow.
   ========================================================================== */
.dvl-div-item {
  position: absolute;
  left: 50%;
  top: 50%;

  display: block;
  margin: 0;
  padding: 0 0.12em;
  white-space: nowrap;

  /* All of these come from the variables at the top of this file. The default
     size uses clamp() rather than a stack of breakpoints: the titles are the
     largest thing on the page and have to track the viewport continuously,
     not in four steps. */
  font-family: var(--dvl-divs-font), "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
  font-size: var(--dvl-divs-size);
  line-height: var(--dvl-divs-leading);
  font-weight: var(--dvl-divs-weight);
  letter-spacing: var(--dvl-divs-tracking);
  color: var(--dvl-divs-color);
  text-decoration: none;
  text-shadow: var(--dvl-divs-shadow);

  /* Blends with the canvas because BOTH live inside .dvl-divs, which is a
     stacking context (position + z-index), and an element blends against
     whatever is painted below it within the nearest such context. Isolate the
     section and this silently stops working. */
  mix-blend-mode: var(--dvl-divs-blend);

  /* The module owns opacity and transform. Declaring the defaults here means
     the first frame is correct before any JS has run. */
  opacity: 1;
  transform-origin: 50% 50%;
  transform: translate3d(0, 0, 0) scale(1);
  /* The individual `translate` property, NOT a -50% inside `transform`. The
     module owns `transform` outright and rewrites it every frame; putting the
     centring in there too would mean every one of those writes had to restate
     it. `translate` composes before `transform`, so the two never collide. */
  translate: -50% -50%;
  will-change: transform, opacity;

  pointer-events: auto;
  cursor: pointer;

  /* NO CSS transition on opacity or transform. Every frame of this movement
     comes from the scroll integrator in the render loop; a CSS transition on
     top of that is a SECOND timeline with its own easing, and the type then
     lags the tape by exactly its own duration. This is the single most
     important line in the file. */
  transition: none;
}

/* The centred title. Weight only — never transform or opacity, which the
   module owns, and never anything that would make it jump as the class crosses
   from one title to the next mid-scrub. The two weights are the same by
   default, because a weight that changes on the centred item snaps at the
   crossover while everything around it is gliding. Set them differently only
   if you want that snap.

   NO `cursor: default` HERE. It used to be, on the reasoning that the centred
   title is "already selected" — which was wrong twice over. The centred title
   is the one that actually navigates to the project page, so it is the single
   most clickable thing on the screen, and it was the only one showing an arrow
   cursor instead of a hand. Every title is clickable: the centred one follows
   its link, the others scrub themselves to the middle. */
.dvl-div-item.is-active {
  font-weight: var(--dvl-divs-weight-active);
}

/* ==== HOLDING THE TITLES AGAINST THE THEME'S LINK STYLES =================
   The titles are real <a> elements, so every global link rule applies.
   Hello's reset.css sets `a:hover, a:active { color: #336 }` — (0,1,1),
   which beats the plain `.dvl-div-item` (0,1,0) and turned every title blue
   under the pointer on the live site. The kit's `.elementor-kit-N a:hover`
   would be (0,2,1). Scoping through the section gives (0,3,0) with the
   pseudo-class, which outranks both without !important. No hover effect is
   wanted at all, so every state just restates the resting look. */
.dvl-divs .dvl-div-item,
.dvl-divs .dvl-div-item:link,
.dvl-divs .dvl-div-item:visited,
.dvl-divs .dvl-div-item:hover,
.dvl-divs .dvl-div-item:focus,
.dvl-divs .dvl-div-item:active {
  color: var(--dvl-divs-color);
  text-decoration: none;
  background: none;
  box-shadow: none;
}

/* ==== HOLDING THE TITLES AGAINST THE THEME'S LINK STYLES =================
   The same contest the arrows lose, for the same reason, and it has to be
   answered separately because these are anchors rather than buttons.

   Elementor's Theme Style emits link colour as `.elementor-kit-NNN a`, which
   is specificity (0,1,1). A plain `.dvl-div-item` is (0,1,0) and loses by one
   class, so the kit's link colour silently replaced the ink. Measured on the
   live page: the titles computed to rgb(58,48,30) instead of white, and under
   `difference` that inverts to rgb(197,207,225) — the pale blue-grey that
   looked like the blend was broken when the blend was working perfectly on
   the wrong colour.

   Scoping through the section gives (0,2,0), which outranks the kit without
   !important. Every link state is listed because the kit styles them all, and
   the whole type block is re-asserted rather than just `color`: the kit sets
   font-family, size and weight on links too, and the next one to slip through
   would be just as invisible to diagnose.
   ========================================================================= */
.dvl-divs .dvl-div-item,
.dvl-divs .dvl-div-item:link,
.dvl-divs .dvl-div-item:visited,
.dvl-divs .dvl-div-item:hover,
.dvl-divs .dvl-div-item:focus,
.dvl-divs .dvl-div-item:active {
  font-family: var(--dvl-divs-font), "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
  font-size: var(--dvl-divs-size);
  line-height: var(--dvl-divs-leading);
  letter-spacing: var(--dvl-divs-tracking);
  color: var(--dvl-divs-color);
  text-decoration: none;
  text-shadow: var(--dvl-divs-shadow);
  background: none;
}

/* Weight stays separate so .is-active can still raise it. */
.dvl-divs .dvl-div-item { font-weight: var(--dvl-divs-weight); }
.dvl-divs .dvl-div-item.is-active { font-weight: var(--dvl-divs-weight-active); }

.dvl-div-item:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 8px;
  border-radius: 2px;
}

/* ==========================================================================
   THE ARROWS
   --------------------------------------------------------------------------
   Real <button>s that FLANK THE CENTRED TITLE rather than sitting at the
   edges of the screen. They are positioned from --dvl-divs-title-half, which
   the module rewrites every frame with half the width of whichever title is
   currently in the middle — interpolated between two titles mid-scrub, so the
   pair glides with the reel instead of jumping when the active item changes.

   They are shortcuts into the same scroll integrator as the wheel, so holding
   one down is not a special case: each click is one more project of travel.
   ========================================================================== */
.dvl-divs__arrow {
  position: absolute;
  top: 50%;
  /* auto, not a number — the arrows blend too, and a z-index here would
     isolate them from the canvas exactly like the reel. DOM order puts them
     above it: the module appends them after the canvas. */
  z-index: auto;

  appearance: none;
  border: 0;
  background: transparent;
  /* Padding is the tap target, not the spacing — the gap is done with
     translate below so that a comfortable 44px touch area never pushes the
     glyph away from the title. */
  padding: 14px;

  font-family: var(--dvl-divs-font), "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
  font-size: var(--dvl-divs-size);
  line-height: 1;
  font-weight: var(--dvl-divs-arrow-weight);
  color: var(--dvl-divs-arrow-color);
  text-shadow: var(--dvl-divs-shadow);
  mix-blend-mode: var(--dvl-divs-blend);

  cursor: pointer;
  opacity: var(--dvl-divs-arrow-opacity);
  /* Opacity may transition; `translate` may NOT. The module rewrites the
     offset every frame from the scroll position, and a transition on it would
     be a second timeline easing toward a target that has already moved — the
     arrows would lag the reel by exactly the transition's duration. */
  transition: opacity 200ms ease;
}

/* The glyph is scaled down inside a full-size box so the button keeps a
   generous hit area while reading as a small mark. */
.dvl-divs__arrow::first-letter { font-size: 1em; }

.dvl-divs__prev {
  left: 50%;
  translate: calc(-100% - var(--dvl-divs-title-half) - var(--dvl-divs-arrow-gap)) -50%;
}
.dvl-divs__next {
  left: 50%;
  translate: calc(var(--dvl-divs-title-half) + var(--dvl-divs-arrow-gap)) -50%;
}

/* ==== HOLDING THE ARROWS AGAINST THE THEME'S BUTTON STYLES ================
   These are real <button> elements, so every global button rule on the site
   applies to them — and Elementor's Theme Style emits its button rules as
   `.elementor-kit-NNN button:hover`, which is specificity (0,2,1). A plain
   `.dvl-divs__arrow:hover` is (0,2,0) and loses by one class, so the kit's
   background and colour take over the moment the pointer lands: measured on
   the live site, the arrows turned into pink filled boxes on hover.

   Scoping through the section gives (0,3,0), which outranks the kit without
   resorting to !important. Every state is listed because the kit styles them
   all, and every property the kit sets has to be answered — declaring only
   `opacity` here is exactly what let it through in the first place.

   This is also why the base rule above is not enough on its own. It happens to
   win today, but only because this particular kit does not set a normal-state
   button background; change one setting in Theme Style and it would lose the
   same way.
   ========================================================================= */
.dvl-divs .dvl-divs__arrow,
.dvl-divs .dvl-divs__arrow:hover,
.dvl-divs .dvl-divs__arrow:focus,
.dvl-divs .dvl-divs__arrow:active {
  background: transparent;
  background-image: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  color: var(--dvl-divs-arrow-color);
  text-decoration: none;
  transform: none;
}

.dvl-divs .dvl-divs__arrow:hover { opacity: 1; }

.dvl-divs__arrow:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.8);
  outline-offset: 2px;
  opacity: 1;
}

/* ==========================================================================
   THE COUNTER
   ========================================================================== */
.dvl-divs__counter {
  position: absolute;
  left: 50%;
  translate: -50% 0;
  bottom: clamp(20px, 5vh, 56px);
  z-index: 3;

  padding: 11px 24px;
  border-radius: 2px;
  background: rgba(12, 12, 12, 0.62);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);

  font: 500 12px/1 ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  letter-spacing: 0.2em;
  color: rgba(255, 255, 255, 0.92);
  white-space: nowrap;
  pointer-events: none;
}

/* ==========================================================================
   THE LIVE REGION
   --------------------------------------------------------------------------
   Announces the centred project. Visually hidden the accessible way — NOT
   display: none and NOT visibility: hidden, both of which remove the element
   from the accessibility tree and make the announcement silent.
   ========================================================================== */
.dvl-divs__live {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ==========================================================================
   ANY OTHER CONTENT IN THE SECTION SITS ABOVE THE CANVAS
   --------------------------------------------------------------------------
   A section heading, an "all projects" link, a logo — anything Elementor puts
   inside .dvl-divs that is not the canvas needs a layer, or the canvas (which
   the module inserts as the FIRST child) covers it.

   Every :not() here is one of this module's OWN children, and excluding them
   is not tidiness — it is required. This selector is (0,2,0); the rules above
   that give the reel, the arrows and the counter `position: absolute` are all
   (0,1,0), so without these exclusions this one rule silently resets the whole
   chrome to `position: relative` and the arrows collapse into the section's
   flex flow at the bottom of the screen. Measured: that is exactly what
   happened the first time this rule was written.
   ========================================================================== */
.dvl-divs > *:not(.dvl-divs__canvas):not(.dvl-divs__reel):not(.dvl-divs__arrow):not(.dvl-divs__counter):not(.dvl-divs__live) {
  position: relative;
  /* THIS ONE MATTERS MOST ON THE LIVE SITE. In the test page the reel is a
     direct child of the section, but under Elementor it is wrapped —
     .dvl-divs > .elementor-widget-html > .elementor-widget-container > .reel —
     so it is the WRAPPER that matches this selector. With `z-index: 2` that
     wrapper became a stacking context and sealed the titles away from the
     canvas on the real page even after the reel itself was fixed.

     `auto` still paints these above the canvas by DOM order, because the
     canvas is inserted as the first child. */
  z-index: auto;
}

/* ==========================================================================
   ONE VIEWPORT, NO SCROLL, FOOTER OVER THE IMAGES
   --------------------------------------------------------------------------
   The module adds `dvl-divs-page` to <html> when it starts and removes it on
   destroy, so these rules only ever apply to a page the reel is actually
   running on. Keying them to a body class set by hand would mean remembering
   to set it, and keying them to a page ID would break the first time the page
   is rebuilt.

   WHY THE SCROLLBAR EXISTS WITHOUT THIS. The section is one viewport tall and
   the footer sits after it in the document, so the page is a viewport PLUS a
   footer and the browser offers a scrollbar for the difference. Making the
   section shorter would only move the problem. Taking the footer out of flow
   is what actually makes the document exactly one viewport.

   The footer is fixed to the bottom and the reel keeps its full height behind
   it, which is what puts the footer over the photographs.

   YOUR FOOTER NEEDS A TRANSPARENT BACKGROUND for that to read as intended —
   Elementor's default is usually a solid fill, which would simply paint a bar
   across the bottom of the image. Set it in the Theme Builder footer's own
   Background settings, not here, so it stays under your control.

   If your footer is not an Elementor Theme Builder footer, add its selector to
   the list below.
   ========================================================================== */
html.dvl-divs-page,
html.dvl-divs-page body {
  height: 100%;
  overflow: hidden;
  /* Belt and braces: iOS Safari will still rubber-band a body that is only
     `overflow: hidden`, which shows a strip of background under the footer. */
  overscroll-behavior: none;
}

html.dvl-divs-page .elementor-location-footer,
html.dvl-divs-page footer[class*="elementor"] {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  /* Above the canvas (0), the reel (2) and the arrows (3), below nothing. */
  z-index: 6;
}

/* The counter would otherwise sit underneath the footer. Lift it clear. */
html.dvl-divs-page .dvl-divs__counter {
  bottom: calc(clamp(20px, 5vh, 56px) + var(--dvl-divs-footer-clear, 0px));
}

/* ==========================================================================
   TABLET — Elementor's own breakpoint, <= 1024px
   The same number every dvl-* module and stylesheet uses, so a width where
   the code changes behaviour is a width where the editor's tabs take over.
   ========================================================================== */
@media (max-width: 1024px) {
  .dvl-divs { --dvl-divs-arrow-gap: 0.7em; }
}

/* ==========================================================================
   MOBILE — Elementor's own breakpoint, <= 767px
   ========================================================================== */
@media (max-width: 767px) {
  .dvl-divs {
    --dvl-divs-size: clamp(20px, 6.2vw, 34px);
    /* On a phone the titles wrap, so a title-hugging arrow would sit beside a
       two-line block and look lost. Push them back out toward the edges. */
    --dvl-divs-arrow-gap: 4vw;
  }

  .dvl-div-item {
    /* Long project names must not run off a 360px screen. Wrapping is allowed
       here and nowhere else, which is why the module re-measures the line box
       AND the title widths on every resize rather than caching them once. */
    white-space: normal;
    text-align: center;
    max-width: 66vw;
  }

  .dvl-divs__arrow {
    padding: 12px 8px;
  }

  .dvl-divs__counter {
    bottom: 22px;
    font-size: 11px;
    padding: 9px 18px;
  }
}

/* ==========================================================================
   REDUCED MOTION
   --------------------------------------------------------------------------
   The module already collapses the easing to 1 when this is set, so the tape
   jumps straight to the target instead of gliding and the dispersion never
   builds up. What is left here is to stop the chrome from moving too.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .dvl-divs__arrow {
    transition: opacity 120ms linear;
  }
}
