/* ==========================================================================
   DIVLAB SERVICES — section 4, "Agency Service"
   --------------------------------------------------------------------------
   Scoped entirely to the section's own classes, plus one opt-in class for the
   site header. No resets, no element selectors, nothing global — safe to
   enqueue from the child theme or paste into Elementor's Custom CSS.
   ========================================================================== */

/* ==========================================================================
   THE SECTION RAMP — works → services → footer
   --------------------------------------------------------------------------
   Three sections, one continuous colour journey: warm neutral at the top of
   the works section, cooling to slate by the time the footer arrives.

   Declared here because this is the middle section and the one whose script
   already owns the same three values (CONFIG.background approach/from/to in
   dvl-services.js). dvl-works.css and dvl-footer.css read them through
   var(..., <hex>) with the literal as a fallback, so any one of the three
   stylesheets still renders correctly on its own.

   WHAT IT LOOKS LIKE WITHOUT THIS. Measured on the live page at 390px:

     #dvl-works      transparent — the stage canvas, which is drifting pink
     #dvl-services   flat rgb(242,241,238)
     #dvl-footer     flat rgb(201,210,212)

   Two instant steps, both landing exactly on a section boundary. On desktop
   the first is softened by paintBackground()'s crossing fade and the second
   by the recede tween, but neither of those runs on mobile — the accordion
   replaces the whole pinned timeline — so there the page simply changed
   colour twice, abruptly.

   The ramp below is pure CSS and therefore identical in both modes, needs no
   scroll listener, and cannot desynchronise from a pin. On desktop
   paintBackground() writes an inline background-image every frame and
   overrides the services gradient — deliberately, since a pinned section has
   to move its colour with pin progress rather than with its own height. Both
   paths use the same endpoints, so they agree at every boundary.
   ========================================================================== */
:root {
  /* The stage canvas's own neutral. #dvl-works rests on this so its top edge
     can dissolve into whatever section 2 left on screen. */
  --dvl-tone-top: #ebeae8;
  /* Where works hands over to services. This is CONFIG.background.approach
     in dvl-services.js — the tone the desktop script starts its own ramp
     from, so the two modes meet at the same value. */
  --dvl-tone-mid: #eae9e7;
  /* The footer's slate, and the end of the journey. Matches
     CONFIG.background.to and .dvl-footer's own background-color. */
  --dvl-tone-bottom: #c9d2d4;
}

.dvl-services {
  position: relative;

  /* ---- LOAD-BEARING. WITHOUT THIS THE WHOLE SECTION IS INVISIBLE. ----
     dvl-stage.js puts a position:fixed, full-viewport canvas at z-index 0 on
     the BODY, and it is the last element in the document. A positioned
     element with `z-index: auto` paints in the same layer as one with
     `z-index: 0`, with ties broken by DOM order — so that canvas paints over
     every section that has not explicitly raised itself, no matter where the
     section sits on the page.

     Measured on the live site while scrolled into this section: the stage
     canvas was filling the viewport with rgba(169,170,169,255) — fully
     opaque — and this section was underneath it. Every row, every prism and
     the whole card were rendering correctly and none of it could be seen.

     dvl-stage.css states the requirement and gives `.dvl-section` z-index 1
     for exactly this reason; the header gets 100 and the footer 2. This
     section carries neither that class nor a z-index of its own, so it needs
     this line. Do not remove it, and give any future full-bleed section the
     same treatment. */
  z-index: 1;

  /* The pin needs a full viewport to hold. */
  min-height: 100vh;
  min-height: 100svh;
  /* The stage canvas's neutral tone, NOT this section's own #f2f1ee.

     #dvl-works is fully transparent, so what sits directly above this
     section is dvl-stage.js's fixed canvas. Resting on the canvas's own tone
     means the boundary starts out invisible; the script then warms it to
     #f2f1ee once the section fills the viewport, and cools it to slate
     during the recede. It also writes a background-image gradient across the
     crossing — see paintBackground() — so background-color alone is the
     no-JS fallback, and it should be the tone that does not seam. */
  background-color: #eae9e7;

  overflow: hidden;

  /* Breathing room around the card, so the background it recedes against is
     actually visible on all four sides once it lifts. */
  display: flex;
  align-items: center;
  /* THE GUTTER IS OWNED HERE AND NOWHERE ELSE.

     Floor 24px, matching the mobile design and every other page. Ceiling
     80px, matching HOME 6, where the heading sits exactly on the 80px grid
     line and the content box runs 80..1840 at the 1920 frame.

     The ceiling was 64px, and the vw term 3.5 — which reached 67.2 at 1920
     and then clamped down to 64. Both moved together so the curve still
     lands on its ceiling at the design width rather than before it:
     4.2vw = 80.6px at 1920.

     ---- THE GUTTER LIVES ON THE PLANE, NOT HERE --------------------------
     Horizontal padding is deliberately ZERO on the section. It was the
     gutter for one revision and that was wrong: the plane is a card that
     recedes in 3D, and insetting the SECTION inset the card with it, so the
     card's left edge landed exactly on the heading. The text had no
     breathing room on the left while the right side carried all the slack
     — visible the moment the plane tilts.

     The card is full-bleed; the gutter is inside it. See
     .dvl-services__plane. */
  padding: clamp(24px, 4vh, 70px) 0;
  box-sizing: border-box;
  margin-bottom: 0 !important;
}

/* Bridge strip at bottom of #dvl-services to prevent any subpixel seam or gap revealing the fixed stage canvas */
#dvl-services::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -3px;
  height: 6px;
  background-color: var(--dvl-tone-bottom, #c9d2d4);
  z-index: 1;
  pointer-events: none;
}

/* ---- THE MIDDLE LEG OF THE RAMP ----
   Holds the hand-off tone through the top fifth of the section — long enough
   that the join with #dvl-works reads as one surface — then cools the rest of
   the way to the footer's slate.

   OVERRIDDEN ON DESKTOP, deliberately. paintBackground() writes the same ramp
   inline against PIN PROGRESS, and inline beats everything here. That is the
   correct split: while the section is pinned its box is not travelling past
   the viewport, so a gradient down its own height would sit perfectly still
   for the whole pin. In accordion mode nothing pins and nothing writes
   inline, so this rule is the ramp. Both paths share the same two endpoints,
   so the boundaries above and below match either way.

   ---- 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-services` (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, which
   suppresses background images on below-the-fold containers until it adds
   .e-lazyloaded. Reasonable 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 because theirs carry it.

   Verified on the live page: without this the computed value was `none`.

   NOTE FOR ELEMENTOR: the section's background COLOUR is still yours — it
   shows through nowhere here because the gradient is opaque, but it remains
   the fallback if this stylesheet is ever dropped. To change the ramp itself,
   edit --dvl-tone-mid / --dvl-tone-bottom at the top of this file, and the
   matching CONFIG.background values in dvl-services.js and dvl-footer.js. */
#dvl-services {
  background-image: linear-gradient(
    to bottom,
    var(--dvl-tone-mid, #eae9e7) 0%,
    var(--dvl-tone-mid, #eae9e7) 22%,
    var(--dvl-tone-bottom, #c9d2d4) 100%
  ) !important;
}

/* --------------------------------------------------------- the prisms ---
   Absolute inside the section and OUTSIDE .dvl-services__plane, which is the
   whole point: the plane receives a 3D transform in phase 3, and anything
   inside it tips and shrinks with the text. The brief is explicit that the
   prisms stay forward at full scale, so they cannot be a child of it.

   z-index sits ABOVE the plane for the same reason — once the card has
   receded, the prisms read as being in front of it. */
.dvl-services__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 3;
  pointer-events: none;
}

/* ------------------------------------------------------- the text plane -
   Everything that recedes lives in here. The transform is written by the
   script; `transform-style` and `backface-visibility` are what stop the
   rotated plane from being flattened or showing its reverse. */
.dvl-services__plane {
  position: relative;
  z-index: 1;
  transform-style: preserve-3d;
  backface-visibility: hidden;
  /* Set from script alongside the transform, but declared so the very first
     frame has an origin rather than defaulting to the centre and lurching. */
  transform-origin: 50% 20%;
  will-change: transform, box-shadow, background-color;

  /* ---- AT REST IT IS THE PAGE, NOT A CARD ----
     No shadow and no tint of its own at p = 0. Any elevation here would be
     visible the instant the section scrolls into view, long before anything
     has lifted — which is what made the card look pasted onto the page
     rather than part of it.

     The script fades BOTH the shadow and a white tint in across phase 3, a
     little ahead of the tilt, so the sheet lifts off the page and only then
     tips back. Both are inline styles, so they win over these declarations
     while animating and fall back to them the moment elevation returns to
     zero. */
  box-shadow: none;
  background-color: transparent;

  /* Geometry is the card's, whether or not it is currently reading as one:
     the width and padding must not change when the elevation arrives, or the
     type would reflow mid-animation.

     ---- WHY THE 1320px CAP IS GONE -------------------------------------
     It was `min(100%, 1320px)`, centred. Against HOME 6 that is the single
     reason nothing in this section could land on its grid line: measured at
     1920, the cap plus this element's own 86.4px padding plus two nested
     Elementor containers at 10px each left a usable column of 1147px where
     the design has 1760. Everything inside was compressed toward the middle
     — the heading sat at x 389 against a design value of 80.

     Full width now, with the section's own gutter (above) providing the
     entire horizontal inset. Vertical padding is untouched: that is real
     rhythm, and the card still needs to breathe when it lifts.

     The prisms do not move. The canvas is appended to the SECTION and sized
     from it — never from this element — and the column axis is a fraction
     of the section width (CONFIG.column.x), which was already full-bleed.
     Verified by measurement, not assumed.

     ---- WHY THE GUTTER IS HERE AND NOT ON THE SECTION -------------------
     This element is a CARD, and it tilts. Put the 80px inset on the section
     and the card inherits it: the card's left edge arrives at x 80, which is
     exactly where the heading starts, so the type collides with the card
     edge and every bit of slack piles up on the right where the tiles fall.

     Full-bleed card, inset contents. The card now spans the whole section
     and the 80px lives inside it, so at 1920 the heading sits 80px clear of
     the card's edge instead of on it — and the composition is symmetric
     rather than left-crushed.

     ---- A FIXED 80px, NOT A CLAMP --------------------------------------
     This was clamp(24px, 4.2vw, 80px), and that was wrong for one reason:
     nothing else on the site is fluid. Measured at 1440 —

       header (.dvl-header)   80px
       #dvl-hero              80px
       #dvl-works             80px
       #dvl-footer            80px
       #dvl-services          60.48px   <- the clamp, and the only outlier

     A fluid gutter and a fixed one agree only where the clamp is pinned to
     its ceiling, which is about 1905px. Everywhere below that the heading
     drifted left of the logo — 20px at 1440 — and the narrower the window
     the worse it got. Matching the site means matching its number, not
     approximating it with a curve that happens to pass through it at one
     width. */
  width: 100%;
  margin: 0 auto;
  padding: clamp(30px, 4vw, 76px) 24px;
  box-sizing: border-box;
}

/* ==========================================================================
   ELEMENTOR'S NESTED CONTAINERS CONTRIBUTE NO HORIZONTAL INSET
   --------------------------------------------------------------------------
   Between the section and the text sit up to four Elementor containers, each
   arriving with its own side padding and, on .e-con-inner, a max-width taken
   from the global content-width setting. They stack:

     #dvl-services            padding 24 (mobile) / 80 (desktop)
     .dvl-services__plane     padding 26 / 86.4      <- e-con-BOXED
     .e-con-inner             max-width 1320
     nested .e-con-full       padding 10
     another .e-con-full      padding 10             <- the rows sit here

   Measured at 375px that put the heading at 60 and every service title at
   70, against a design that puts both at 24. Nothing was overriding the
   gutter — it was being added to three times over.

   Descendants only. `#dvl-services .e-con-full` cannot match the section
   itself, so the gutter set above survives; only the containers inside it
   are flattened. Horizontal only — vertical padding is spacing and stays.

   .dvl-services__plane is EXCLUDED, and that exclusion is the gutter. It is
   an `e-con-boxed`, so an unqualified match would zero the very padding that
   now holds the 80px inset, and the heading would go straight back onto the
   card's edge. It is also the reason this list names e-con-boxed at all:
   matching only e-con-full left 26px behind and the gutter stalled at 50px.
   ========================================================================== */
#dvl-services .e-con-full,
#dvl-services .e-con-boxed:not(.dvl-services__plane),
#dvl-services .e-con-inner {
  padding-left: 0 !important;
  padding-right: 0 !important;
}

#dvl-services .e-con-inner {
  max-width: none !important;
}

/* ==========================================================================
   THE TWO-COLUMN SPLIT — 39.3 / 60.7
   --------------------------------------------------------------------------
   HOME 6 is a two-column section: the heading and <AGENCY-BOX> on the left
   gutter, the six service rows in a right-hand column. Measured in the
   frame, against the 1760px content box between the 80px gutters:

     heading     x 80                 -> 0%
     service row x 772   (772-80)/1760 = 39.3%

   So the left column is 39.3% and the right column is the remaining 60.7%,
   and the boundary between them IS the rows' left edge. That is the whole
   specification — no fixed pixel column widths, so it holds at any width.

   ---- WHY THE GAP IS ZEROED -------------------------------------------
   Elementor had a 5% column-gap on the inner container. A gap is a third
   number that the 39.3% has to be computed around, and the moment anyone
   changes it in the editor the rows leave their grid line. Folding it into
   the column widths makes the split self-contained: 39.3 + 60.7 = 100, and
   the rows sit exactly where the left column ends.

   Unboxing alone put the rows at 691 (the columns were 524 + 5% + 1082,
   which is not the design ratio). With this they land on 766 — the design's
   772 scaled by the 1905/1920 the scrollbar leaves.

   Desktop only: below 768 the accordion stacks these two into one column
   and any width here would fight it.
   ========================================================================== */
@media (min-width: 1201px) and (min-height: 541px) {
  /* The site gutter, as a fixed value — see the note on
     .dvl-services__plane. 24px below this breakpoint, 80px above it, which
     is what the header, hero, works and footer all do. Desktop only. */
  #dvl-services:not(.dvl-services--accordion) .dvl-services__plane {
    padding-left: 80px;
    padding-right: 80px;
  }

  #dvl-services:not(.dvl-services--accordion) .e-con-inner {
    column-gap: 0 !important;
  }

  #dvl-services:not(.dvl-services--accordion) .dvl-services__head {
    flex: 0 0 39.3% !important;
    width: 39.3% !important;
    max-width: none !important;
  }

  #dvl-services:not(.dvl-services--accordion) .dvl-services__list {
    flex: 0 0 60.7% !important;
    width: 60.7% !important;
    max-width: none !important;
  }
}

/* ==========================================================================
   KILL ELEMENTOR'S TRANSITIONS — load-bearing, not tidying
   --------------------------------------------------------------------------
   Elementor ships this on every container:

     .e-con:where(:not(.e-div-block-base)) {
       transition: background .3s, border .3s, box-shadow .3s,
                   transform var(--e-con-transform-transition-duration, .4s);
     }

   THE SECTION ITSELF IS THE CRITICAL ONE. When a pin ends, ScrollTrigger
   stops using position:fixed and instead writes an inline
   `transform: translate(0px, <pinDistance>px)` to hold the element at the
   BOTTOM of its pin-spacer. With a transition on `transform` that write
   never lands — measured on the live site, the inline style read
   `translate(0px, 1980px)` while the computed transform stayed
   `matrix(1,0,0,1,0,0)`.

   The element therefore stayed at the TOP of a 2880px spacer, leaving the
   spacer's 1980px of padding-bottom as a huge empty void under the section
   — the section appeared to vanish and the page below it looked blank.
   Fixing it moved the section from -2276px to its correct -296px.

   This is the SAME defect that caused the hero's 1170px text jump at unpin,
   fixed in dvl-stage.css via `.dvl-section`. This section does not carry
   that class, so it needs its own rule — omitting it is what broke it.

   The children matter too, for a different reason: their transform, filter,
   opacity and box-shadow are rewritten every frame by GSAP or by
   applyRecede(). A transition on a property a script drives per frame does
   not smooth it, it fights it — lagging the element a full transition
   behind the scroll. Nothing here is animated by CSS, so nothing is lost.
   ========================================================================== */
.dvl-services,
.pin-spacer > .dvl-services,
.dvl-services__plane,
.dvl-service-item,
.dvl-service-title,
.dvl-service-desc {
  transition: none !important;
}

/* --------------------------------------------------------- service rows - */
.dvl-service-item {
  position: relative;
  cursor: pointer;
}

/* The description sits exactly on top of its own title rather than after it,
   so the swap happens in place. Absolute against the row, which is why the
   row is position:relative above.

   Height is NOT reserved for it: the title defines the row's box, and the
   description is an overlay. That keeps the list's rhythm identical whether
   anything is hovered or not — reserving space for both would leave a gap
   under every row. */
.dvl-service-title {
  position: relative;
  z-index: 1;
  /* Named explicitly so the blur tween has something to interpolate FROM.
     Animating to blur() from `none` is not interpolable in every engine and
     can snap rather than ramp. */
  filter: blur(0px);
  will-change: transform, filter, opacity;
}

.dvl-service-desc {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  width: min(52ch, 100%);
  /* Never intercepts the hover it is reporting on. Without this, moving the
     cursor onto the revealed copy would register as leaving the row, the row
     would reset, the copy would vanish, the cursor would be back over the
     title, and the two states would strobe against each other.

     Kept here rather than only in script so it holds from the first frame,
     and the script sets it on every description it touches as well. */
  pointer-events: none !important;
  /* Opacity is set from script, not here: if the module never loads, the
     copy stays readable in normal flow instead of being invisible for good. */
}

/* ==========================================================================
   GLOBAL HEADER — restored over this section
   --------------------------------------------------------------------------
   Added by the script when section 4 comes into view and removed only if the
   visitor scrolls back above it. The script animates opacity and y; this
   class supplies the pinning and a stacking order that clears the section's
   own canvas.

   If the header is already fixed — .dvl-header--overlay is, from
   dvl-stage.css — every declaration here is a harmless no-op. It exists for
   the case where the header is a normal in-flow Elementor block that has
   scrolled away entirely, which cannot be brought back by opacity alone.

   The opacity/visibility pair are fallbacks only: the script writes both
   inline while tweening, and inline wins over a class.
   ========================================================================== */
.dvl-header--restored {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  width: 100%;
  z-index: 60;
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}

/* ------------------------------------------------------------ fallbacks - */

/* No WebGL, or the .glb never arrived: the section is text and layout only,
   which is entirely readable. Nothing here depends on the prisms. */
.dvl-services:not(.dvl-services--ready) .dvl-services__canvas {
  display: none;
}

/* Touch: there is no hover, so the descriptions can never be revealed by
   pointer. Show them in flow underneath their titles instead of hiding copy
   the visitor can never reach.

   This stays as the FALLBACK for the case where the accordion never
   initialises — script blocked, an old engine, the module not enqueued. The
   accordion block below is scoped to .dvl-services--accordion, a class only
   the script adds, so if it never runs the copy is simply all visible. That
   is the correct failure: readable, unstyled, nothing hidden behind a
   control that does not exist. */
@media (hover: none) {
  /* :not(.dvl-services--accordion) is load-bearing. This rule carries
     `opacity: 1 !important` — necessary when it is the only thing making the
     copy visible — and an unscoped !important outranks the accordion's own
     `opacity: 0`, so every closed panel stayed fully opaque and the fade had
     nothing to animate. Height clipping hid it, which made the symptom
     invisible rather than absent.

     Scoping it also keeps it doing its real job at 768-1024px, where a
     tablet has no hover and no accordion either. */
  .dvl-services:not(.dvl-services--accordion) .dvl-service-desc {
    position: static;
    transform: none;
    opacity: 1 !important;
    margin-top: .4em;
  }
  .dvl-services__canvas {
    display: none;
  }
}

/* ==========================================================================
   TOUCH, TABLET & MOBILE ACCORDION (ALL NON-DESKTOP BREAKPOINTS)
   --------------------------------------------------------------------------
   Applied whenever dvl-services.js activates ServicesAccordion (.dvl-services--accordion).
   Title stacks at top, and service items become tap-to-expand accordion tabs
   with smooth animations, right-to-down rotating chevrons, and clean borders.
   ========================================================================== */
@media (max-width: 1400px), ((max-height: 540px) and (orientation: landscape)), (hover: none), (pointer: coarse) {

  /* The 24px gutter is handled once, unscoped, in "ELEMENTOR'S NESTED
     CONTAINERS CONTRIBUTE NO HORIZONTAL INSET" above — the same stacking
     problem produces the 60/70px inset here and the 389px one on desktop,
     so it is solved in one place rather than per breakpoint. */

  /* ==== VERTICAL RHYTHM, FROM home-mobile-9 AND -10 ====================
     Measured in the design at 402 wide:

       <AGENCY-BOX> bottom  363
       first row top        479     -> 116px of air
       row title bottom     513
       description top      578     ->  65px
       description bottom   703
       next row top         769     ->  66px

     Live, before this block: 20px under the header and 26px between a row
     title and its copy. The section read as a tight list rather than the
     open one in the design.

     The header gap is put on the LIST rather than the head, so it is one
     number measured from the thing it actually separates; the 20px it
     replaces came from the parent container's row-gap, which is not a
     spacing decision anyone made here.

     ---- THE ROW GAPS WERE OVER-INFLATED AND ARE NOW COMPACT -------------
     The 65/66 above came from subtracting Figma TEXT-NODE coordinates —
     title box bottom 513 against description box top 578. That arithmetic
     is right and the conclusion was wrong: a Figma text node's box carries
     its own leading, so the number includes space that is already inside
     the two boxes. Rendered, it produced roughly double the air in the
     frame, which is the inflation in the review screenshot.

     The visible gap in the design is about one line of the description's
     own 25px leading above it and a little more below. 18 and 24 land
     there, measured to the GLYPHS rather than the boxes — which is the
     measurement that was wrong the first time.

     The header gap is unchanged at 116: that one is a gap between two
     separated blocks with no shared leading, so the subtraction holds. */
  .dvl-services--accordion .e-con-inner,
  #dvl-services.dvl-services--accordion .e-con-inner {
    flex-direction: column !important;
    display: flex !important;
  }

  .dvl-services--accordion .dvl-services__head,
  #dvl-services.dvl-services--accordion .dvl-services__head {
    flex: 0 0 100% !important;
    width: 100% !important;
    max-width: 100% !important;
  }

  .dvl-services--accordion .dvl-services__list,
  #dvl-services.dvl-services--accordion .dvl-services__list {
    flex: 0 0 100% !important;
    width: 100% !important;
    max-width: 100% !important;
  }

  .dvl-services--accordion .dvl-services__list {
    margin-top: var(--dvl-svc-head-gap, 96px) !important;
  }

  @media (min-width: 768px) and (max-width: 1600px) {
    .dvl-services--accordion .dvl-service-title {
      font-size: clamp(26px, 3.2vw, 36px) !important;
      line-height: 1.25 !important;
    }
  }

  @media (max-height: 540px) and (orientation: landscape) {
    .dvl-services--accordion .dvl-services__list {
      margin-top: 36px !important;
    }
    .dvl-services--accordion .dvl-service-title {
      font-size: clamp(20px, 5.6vh, 28px) !important;
      line-height: 1.25 !important;
    }
  }

  .dvl-services--accordion .dvl-services__canvas {
    display: none !important;
  }

  .dvl-services--accordion .dvl-services__plane {
    transform: none !important;
    perspective: none !important;
  }

  .dvl-services--accordion .dvl-service-desc {
    padding-top: var(--dvl-svc-title-desc, 18px) !important;
    padding-bottom: var(--dvl-svc-desc-line, 24px) !important;
  }

  /* DESCRIPTION TYPE — IBM Plex Mono w400 14/25, per home-mobile-10.

     Live it was rendering Mynerve 16/24 in rgb(51,51,51): the theme's
     default face and colour, not a choice — the widget simply has no
     typography set on it. This is the same unstyled copy flagged in the
     HOME 6 audit for both breakpoints.

     ---- WHY THIS IS NOT :where() ANY MORE -------------------------------
     It was, so the Elementor panel could override it. That only works while
     the panel has nothing set. Measured on the live page the description is
     an Elementor HEADING widget carrying real per-element CSS —

       IBM_Plex_Mono  16px / lh 16px / ls -1px

     — which beats a zero-specificity rule outright, so the correct 14/25/0
     never applied. The family is right and the three metrics are not.

     Specific and flagged, therefore. The editor's own values should be
     corrected to match (Typography -> Mobile: 14 / 25 / 0), and once they
     do this rule becomes a no-op rather than a fight. Until then it is the
     only thing putting the design's numbers on the page. */
  #dvl-services .dvl-service-desc,
  #dvl-services .dvl-service-desc .elementor-heading-title,
  #dvl-services .dvl-service-desc p {
    font-family: 'IBM_Plex_Mono', ui-monospace, monospace !important;
    font-weight: 400 !important;
    font-size: 14px !important;
    line-height: 25px !important;
    letter-spacing: 0 !important;
    color: var(--divlab-font-dark, #3a301e) !important;
  }

  /* The row is a control. Give it a real tap target and somewhere to put the
     indicator — 44px is the accepted minimum, and a title set in a large
     display face usually clears it on its own, but not the short ones. */
  .dvl-services--accordion .dvl-service-title {
    position: relative;
    padding: .55em 2.2em .55em 0;
    min-height: 44px;
    box-sizing: border-box;
    /* Removes the 300ms tap delay and the grey flash on iOS without
       disabling text selection anywhere else. */
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
  }

  /* A chevron, drawn rather than shipped: two borders on a rotated square is
     one element and no request.

     ---- POINTING RIGHT, NOT DOWN ----------------------------------------
     home-mobile-9 shows a ">" against every closed row — right-pointing.
     This was rotate(45deg), which with a right+bottom border pair points
     DOWN, and opened to 225deg (up). Closed is now -45deg so it reads as
     the ">" in the frame, and opening turns it a quarter-turn to point down
     at the panel it just revealed.

     translateY differs between the two states on purpose. A square with two
     borders is not visually centred on its own box once rotated: the
     right-pointing form is symmetric about the horizontal axis and sits
     correctly at -50%, while the down-pointing form's mass drops below
     centre and needs -70% to look level with the title.

     ---- EXPLICIT COLOURS, NOT currentColor + opacity --------------------
     It used to inherit the title's colour at .45 / .9 opacity. The design
     specifies two real values — #9d988f closed, #3a301e open — and a faded
     tint of the title colour is not the same thing as either: the closed
     chevron came out as 45% of #3a301e over the section's #eae9e7, which is
     a warmer, darker grey than the #9d988f the design asks for.

     Both are exposed as custom properties, and both default to the site
     tokens rather than to literals. */
  .dvl-services--accordion .dvl-service-title::after {
    content: '';
    position: absolute;
    right: .35em;
    top: 50%;
    width: .42em;
    height: .42em;
    border-right: 2px solid var(--dvl-chevron-rest, var(--logo-light, #9d988f));
    border-bottom: 2px solid var(--dvl-chevron-rest, var(--logo-light, #9d988f));
    transform: translateY(-50%) rotate(-45deg);
    transform-origin: center;
    opacity: 1;
    transition: transform .42s cubic-bezier(.22, .61, .36, 1),
                border-color .3s ease;
    pointer-events: none;
  }

  .dvl-services--accordion .dvl-service-item.is-open .dvl-service-title::after {
    border-right-color: var(--dvl-chevron-open, var(--divlab-font-dark, #3a301e));
    border-bottom-color: var(--dvl-chevron-open, var(--divlab-font-dark, #3a301e));
    transform: translateY(-70%) rotate(45deg);
  }

  /* ---- the panel ----
     `transition` carries !important because the block near the top of this
     file kills transitions on .dvl-service-desc outright — correct while the
     desktop build rewrites transform and opacity every frame from script,
     wrong here where CSS is the only thing animating. This selector is more
     specific, so it wins, and it re-enables ONLY the two properties the
     accordion drives.

     overflow: hidden is what makes max-height clip rather than overflow.
     The height itself is written by the script from the panel's measured
     scrollHeight — see the note in dvl-services.js. */
  .dvl-services--accordion .dvl-service-desc {
    position: static;
    transform: none;
    width: auto;
    max-height: 0;
    overflow: hidden;
    opacity: 0;
    margin-top: 0;
    transition: max-height .42s cubic-bezier(.22, .61, .36, 1),
                opacity .26s ease,
                margin-top .42s cubic-bezier(.22, .61, .36, 1) !important;
  }

  .dvl-services--accordion .dvl-service-item.is-open .dvl-service-desc {
    opacity: 1 !important;
    margin-top: .5em;
  }

  /* A hairline between rows so a closed list reads as a list of controls
     rather than a paragraph of headings. */
  .dvl-services--accordion .dvl-service-item {
    border-bottom: 1px solid currentColor;
    border-bottom-color: rgba(58, 48, 30, .14);
  }
  .dvl-services--accordion .dvl-service-item:first-child {
    border-top: 1px solid rgba(58, 48, 30, .14);
  }

  /* Keyboard users must be able to see which row they are on. Scoped to
     :focus-visible so it never appears on tap. */
  .dvl-services--accordion .dvl-service-title:focus-visible {
    outline: 2px solid rgba(58, 48, 30, .55);
    outline-offset: 3px;
    border-radius: 2px;
  }
}

/* Someone who has asked for less motion still gets the accordion — it is a
   control, not an effect — but it opens and closes immediately. */
@media (prefers-reduced-motion: reduce) {
  .dvl-services--accordion .dvl-service-desc,
  .dvl-services--accordion .dvl-service-title::after {
    transition: none !important;
  }
}

@media (prefers-reduced-motion: reduce) {
  .dvl-service-title {
    filter: none !important;
    transform: none !important;
  }
  .dvl-services__plane {
    transform: none !important;
  }
}

/* ==========================================================================
   RESPONSIVE (NON-DESKTOP) TOP SPACING
   --------------------------------------------------------------------------
   Slightly compact top breathing room on tablet and mobile so distance from
   "Explore All Divs" down to Agency Services is well balanced (~56px - 64px),
   keeping it noticeably larger than Explore's top gap (~28px) while removing
   excessive void between the sections.
   ========================================================================== */
@media (max-width: 1400px), (hover: none), (pointer: coarse), ((max-height: 540px) and (orientation: landscape)) {
  #dvl-services {
    padding-top: clamp(18px, 2.8vh, 26px) !important;
  }
  #dvl-services .dvl-services__plane {
    padding-top: clamp(16px, 2.4vw, 22px) !important;
  }
}

/* ==========================================================================
   AGENCY SERVICES HORIZONTAL GUTTER SYNCHRONIZATION WITH HEADER & FOOTER
   --------------------------------------------------------------------------
   Aligns Agency Services content (heading, divider lines, accordion items)
   exactly with the Header logo/actions and Footer on all breakpoints:
   - Tablet (768px - 1400px): 80px gutter
   - Mobile Landscape: 80px + safe-area gutter
   - Mobile Portrait: 24px gutter
   ========================================================================== */
@media (min-width: 768px) and (max-width: 1600px) 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-services .dvl-services__plane,
  .dvl-services--accordion .dvl-services__plane {
    padding-left: 80px !important;
    padding-right: 80px !important;
  }
}

@media (max-height: 540px) and (orientation: landscape) {
  #dvl-services {
    padding-top: calc(env(safe-area-inset-top, 0px) + 72px) !important;
  }
  #dvl-services .dvl-services__plane,
  .dvl-services--accordion .dvl-services__plane {
    padding-left: calc(env(safe-area-inset-left, 0px) + 24px) !important;
    padding-right: calc(env(safe-area-inset-right, 0px) + 24px) !important;
  }
}

@media (max-width: 767px) and (orientation: portrait) {
  #dvl-services .dvl-services__plane,
  .dvl-services--accordion .dvl-services__plane {
    padding-left: calc(env(safe-area-inset-left, 0px) + 24px) !important;
    padding-right: calc(env(safe-area-inset-right, 0px) + 24px) !important;
  }
}


