/* ==========================================================================
   DIVLAB CONTACT — 100vh, non-scrolling contact page
   --------------------------------------------------------------------------
   Scoped entirely to the contact section's own classes. No resets, no bare
   element selectors, nothing global except the two scroll-lock classes
   (which are only ever applied by dvl-contact.js, on this page).

   WHAT IS TUNABLE WITHOUT TOUCHING THIS FILE
   Every colour, font, size and rhythm below is a custom property on
   #dvl-contact. Elementor's Advanced > Custom CSS can restyle the whole page
   with one block:

       #dvl-contact { --dvl-contact-accent: #e8927a; --dvl-contact-gap: 10px; }

   Elementor's own Typography and Colour pickers cannot reach most of this —
   they only emit CSS for widgets Elementor renders, and the headline lives in
   an HTML widget so the tile can sit inside the word.

   THE HEADLINE IS ORDINARY DOM TYPE. Only the "o" of TOUCH is WebGL, in a
   canvas that lives inside that letter's own inline box — so the gradient
   below is a normal background-clip:text, and the rest of the headline stays
   selectable, searchable and sub-pixel sharp.
   ========================================================================== */

/* ==========================================================================
   THE SCROLL LOCK
   Applied by dvl-contact.js only (CONFIG.lockScroll), never by this file:
   this stylesheet may be enqueued site-wide, and freezing a page that is
   supposed to scroll is a much worse failure than a contact page that does.
   overscroll-behavior stops the rubber-band on iOS, which otherwise drags
   the whole fixed layout up off the top of the screen.
   ========================================================================== */
html.dvl-contact-lock,
body.dvl-contact-lock {
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
}

/* ==========================================================================
   THE WORDPRESS ADMIN BAR
   --------------------------------------------------------------------------
   WordPress prints `html { margin-top: 32px !important; }` for logged-in
   users (46px below 783px wide). On a normal page that just pushes the
   content down and the page grows. Here the document becomes
   `32px + 100dvh` against a viewport of `100dvh`, and the scroll lock's
   `overflow: hidden` takes the difference off the BOTTOM — so the Send
   button and the base row vanish for editors while looking perfect to
   logged-out visitors, which is the worst possible way for this to fail.

   Shortening the section by the bar's height is the fix. It cannot be done
   by un-setting the margin: that rule carries !important and is re-applied
   by core on every load.

   The breakpoint is WordPress's own (782px), not Elementor's 767 — the admin
   bar wraps to two rows at its own width and nothing else here cares.
   ========================================================================== */
body.dvl-contact-lock.admin-bar #dvl-contact {
  height: calc(100vh - 32px);
  height: calc(100dvh - 32px);
}
@media screen and (max-width: 782px) {
  body.dvl-contact-lock.admin-bar #dvl-contact {
    height: calc(100vh - 46px);
    height: calc(100dvh - 46px);
  }
}

/* ==========================================================================
   THE THEME BUILDER CHROME
   --------------------------------------------------------------------------
   Nothing here positions the header or the footer. An earlier build pinned
   the header with `position: fixed` on the assumption it was an overlay;
   measured on the live site it is `position: static` and 130px tall, and the
   footer is static and 140px. Pinning it took it out of the flow, which left
   the section a full viewport tall INSIDE a document that was taller than
   the viewport and could not scroll — so the real footer was unreachable and
   this section drew a base row of its own to compensate. That duplicate is
   what shows on a phone.

   The height is given back instead (see the section rule above), and the
   shared footer simply renders. dvl-contact.js measures it, handles the
   overlay case, and sets .dvl-contact--has-footer so the base row below
   stands down.
   ========================================================================== */

/* ==========================================================================
   SECTION
   ========================================================================== */
#dvl-contact {
  /* ---- palette ---- */
  /* MUST match CONFIG.glass.pageTone in dvl-contact.js: that value is the
     renderer's clear colour, which is what the prism refracts. Change one
     and the glass carries a tint from a page that no longer exists. */
  --dvl-contact-bg: #ffffff;
  /* THE SITE'S OWN TOKENS, read from the live Elementor kit rather than
     sampled off a screenshot:
       Divlab font dark   #3A301E   (--e-global-color-54ba015)
       Divlab font light  #3A301E80 (--e-global-color-3f48712) — the same
                                    hue at 50%, not a separate grey. */
  --dvl-contact-ink: #3A301E;       /* headline gradient, dark end */
  --dvl-contact-ink-fade: #b7b1a6;  /* headline gradient, light end */
  --dvl-contact-ink-soft: #3A301E80;/* field captions */
  --dvl-contact-accent: #f3a78d;
  --dvl-contact-halo: rgba(243, 167, 141, 0.42);
  /* The prism's cast shadow. Warm rather than grey: a neutral shadow under a
     peach object on a white page reads as dirt. */
  --dvl-contact-shadow: rgba(186, 122, 100, 0.34);
  /* The fields are a tone plus a diffuse halo of the SAME tone — that halo
     is the feathered edge, and it is why they have no border. */
  --dvl-contact-field: rgba(228, 226, 221, 0.85);
  --dvl-contact-field-glow: rgba(228, 226, 221, 0.7);
  --dvl-contact-field-edge: #f6f6f5;

  /* ---- the letter ----
     The canvas's size as a percentage of the "o" slot. Paired with
     CONFIG.tile.fill in the JS — see THE LETTER CANVAS below. */
  --dvl-o-canvas: 200%;

  /* ---- type ---- */
  /* IBM_Plex_Mono with UNDERSCORES: that is the family name the site's own
     @font-face rules register, and "IBM Plex Mono" does not match it. */
  --dvl-contact-font-display: "Inter", "Helvetica Neue", Helvetica, Arial,
                              sans-serif;
  --dvl-contact-font-mono: "IBM_Plex_Mono", "IBM Plex Mono", ui-monospace,
                           "SFMono-Regular", Menlo, Consolas, monospace;

  /* ---- rhythm ---- */
  /* Floor raised 18 -> 24 so the mobile gutter matches every other page and
     the design's own 24px inset. The vw term and ceiling are untouched. */
  --dvl-contact-pad: clamp(24px, 4.2vw, 62px);
  --dvl-contact-gap: 8px;
  --dvl-contact-radius: 6px;

  /* ---- THE HEIGHT BUDGET ----
     The page is exactly one viewport tall and cannot scroll, so vertical
     space is a fixed sum that has to balance. These four are the terms.

     head-top      space under the overlay header, before the headline.
     base-row      the social/email row's own height. It is position:absolute,
                   so it contributes NOTHING to the flow and the column above
                   would happily run straight over it. Reserving it here as
                   padding is what makes that impossible rather than unlikely.
     base-bottom   how far that row sits off the bottom edge.
     base-clear    the gap between the Send button and the row.

     Sized with min() of a vh and a vw term, so a viewport that is WIDE AND
     SHORT is governed by its height. That combination is what broke the
     previous build: everything was clamped on vw alone, so dragging a window
     wider while it stayed short grew the headline past what the height could
     pay for, and the form ran into the footer. */
  /* THE FLOOR UNDER head-top. The header floats (see THE HEADER, above), so
     nothing else is holding the headline off it — on a short viewport the vh
     term alone drops the type straight under the logo. Measured at 1740x640
     before this existed: the headline's top sat 6px ABOVE the header's
     bottom edge.

     This is the header's height PLUS a little air, not the height alone —
     84px assumes a header of about 70. Set it to your own if it differs; it
     is the one number on this page that has to know about something outside
     it. */
  --dvl-header-clear: 84px;

  /* THE RIGHT-HAND GRID LINE.
     In the comp the right stem of the "h" of Touch and the right edge of the
     form share one vertical: at the 1920 frame both land at x=1545, i.e.
     375px in from the edge. The headline and the form both hang off this,
     so the alignment cannot drift apart when either is retuned. */
  --dvl-right-inset: clamp(var(--dvl-contact-pad), 19.5vw, 375px);

  /* Space above the headline. The chrome is IN FLOW and already subtracted
     from the section's height, so this only has to look right — except when
     a header is overlaid, where --dvl-header-clear (written by the module)
     carries its height and this has to clear it too. */
  /* 8vh, not the 14vh this carried while the header was (wrongly) pinned
     as an overlay: the chrome is in the flow now, so the section starts
     BELOW the header and this is pure composition. On a 1080 screen the
     section is only 810px tall, and the headline alone is 269 of it. */
  --dvl-head-top: calc(var(--dvl-header-clear, 0px) + clamp(12px, 8vh, 96px));
  --dvl-base-row: 44px;
  --dvl-base-bottom: clamp(14px, 2.6vh, 34px);
  --dvl-base-clear: clamp(10px, 2vh, 22px);

  position: relative;
  z-index: 1;               /* see THE Z-INDEX TRAP below */
  box-sizing: border-box;
  width: 100%;

  /* 100dvh where it exists — on iOS Safari 100vh is the tallest the viewport
     ever gets, so the bottom row would sit under the browser chrome until the
     URL bar collapsed. The 100vh line stays as the fallback for engines that
     do not know dvh, and must come first. */
  /* The Theme Builder header and footer are IN THE FLOW on this site
     (measured live: 130px and 140px, both position:static and transparent),
     so a full-viewport section would push the footer below the fold on a
     page that cannot scroll. Give their height back instead.
     --dvl-chrome-flow is written by dvl-contact.js; the 0px fallback is what
     a no-JavaScript page gets, and is also correct if the chrome is absent. */
  height: calc(100vh - var(--dvl-chrome-flow, 0px));
  height: calc(100dvh - var(--dvl-chrome-flow, 0px));

  /* The floor has to know about the chrome too. A flat `min-height: 460px`
     wins against the height above whenever the viewport is short, and the
     section then grows back past what the screen can show — measured at
     1024x640, that pushed the footer off the bottom of a page that cannot
     scroll. min() keeps the floor from ever exceeding what is left. */
  min-height: min(460px, calc(100vh - var(--dvl-chrome-flow, 0px)));
  min-height: min(460px, calc(100dvh - var(--dvl-chrome-flow, 0px)));

  overflow: hidden;
  background: var(--dvl-contact-bg);
  color: var(--dvl-contact-ink);
  font-family: var(--dvl-contact-font-mono);
}

/* ==== THE Z-INDEX TRAP ====================================================
   dvl-stage.js puts ONE fixed, full-viewport canvas on <body> at z-index 0,
   last in the DOM. `z-index: auto` and `z-index: 0` share a stacking layer,
   DOM order breaks the tie, and the stage canvas is last — so any full-bleed
   section without an explicit z-index is painted OVER by it. This has bitten
   works, services and the footer in turn. The explicit `z-index: 1` above is
   the fix, and it is why this rule exists at all even though the contact page
   normally does not load the stage.
   ========================================================================== */

/* ==========================================================================
   THE LETTER CANVAS
   --------------------------------------------------------------------------
   Positioned and sized ENTIRELY here, in percentages of the slot it lives
   in — dvl-contact.js measures nothing but its pixel size. The slot is sized
   in `em`, so this whole assembly tracks the headline's fluid clamp() and
   every breakpoint for free: there is no JS "sync the canvas to the letter"
   pass that can drift on a reflow, a zoom or a webfont swap.

   IT IS BIGGER THAN THE LETTER, ON PURPOSE. A triangle rolling through 360
   degrees sweeps its circumcircle; a canvas cropped to the letter's own box
   would shear the corners off on every diagonal. --dvl-o-canvas is that
   overspill, and CONFIG.tile.fill in the JS is its other half — raise one
   without the other and the prism either clips or shrinks.
   ========================================================================== */
.dvl-contact__canvas {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 2;                     /* in FRONT of the type it overlaps */
  width: var(--dvl-o-canvas, 200%);
  height: var(--dvl-o-canvas, 200%);
  transform: translate(-50%, -50%);
  display: block;
  /* The canvas overhangs the neighbouring glyphs. Without this it would eat
     clicks and text selection across a box nearly twice the letter's size,
     for a decoration that has nothing to click. */
  pointer-events: none;
  /* THE CAST SHADOW. The filter reads the canvas's own alpha, so what it
     casts is the silhouette of the PRISM, turning with it, for no extra draw
     call — and unlike a shadow drawn into the scene it is not clipped at the
     canvas edge. dvl-contact.js writes only the two offsets and the blur,
     from the cursor's bearing (see syncShadow); the colour and the whole
     decision to have a shadow at all stay here.

     The fallbacks matter: they are what the first frame uses, before any
     pointer has moved, and they are the whole shadow if CONFIG.shadow is
     switched off. */
  filter: drop-shadow(var(--dvl-o-shadow-x, 0px)
                      var(--dvl-o-shadow-y, 4px)
                      var(--dvl-o-shadow-blur, 12px)
                      var(--dvl-contact-shadow, rgba(186, 122, 100, 0.34)));

  /* Faded in by .dvl-contact--live, so the prism arrives rather than popping
     in whenever the .glb happens to land. */
  opacity: 0;
  transition: opacity 0.45s ease;
}
.dvl-contact--live .dvl-contact__canvas { opacity: 1; }

/* Everything the visitor can click lives above the canvas. */
.dvl-contact__inner {
  position: relative;
  z-index: 1;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  height: 100%;
  /* The bottom padding is the base row's SAFE AREA, computed rather than
     eyeballed: the row is absolutely positioned and therefore invisible to
     the flow, so this is the only thing standing between the Send button and
     the social icons. Everything in the column lives above it, always. */
  padding: var(--dvl-head-top) var(--dvl-contact-pad)
           calc(var(--dvl-base-bottom) + var(--dvl-base-row) + var(--dvl-base-clear));
}

/* ==========================================================================
   HOW THE COLUMN ABSORBS A SHORT VIEWPORT
   --------------------------------------------------------------------------
   The headline and the Send button keep their size; the MESSAGE BOX gives way
   first, down to a small minimum, and grows back to its authored height when
   there is room. So the page fits by making the one element that can afford
   it smaller, instead of pushing the bottom of the form off the screen.

   `min-height: 0` on every link in the chain is what makes that work at all:
   a flex item's default minimum is its content size, so without these the
   textarea refuses to shrink and the overflow simply moves outside the
   section, which is exactly the bug this replaces.
   ========================================================================== */
.dvl-contact__head { flex: 0 0 auto; }

.dvl-contact__form {
  display: flex;
  flex-direction: column;
  /* SHRINK ONLY — 0 1 auto, never 1 1 auto. Growing would pull the column
     down to the base row on a tall screen and open a gap between the message
     box and the Send button, because the box has a cap and the slack has to
     go somewhere. Top-packed with slack at the bottom is the authored look. */
  flex: 0 1 auto;
  min-height: 0;
}

.dvl-contact__lead { flex: 0 0 auto; }
.dvl-contact__send { flex: 0 0 auto; }

.dvl-contact__fields {
  flex: 1 1 auto;
  min-height: 0;
}

/* The message field is the last one, and the only one that flexes.

   THE CAP IS ON THE FIELD, NOT ON THE TEXTAREA. The caption is positioned
   against the FIELD's bottom edge, so capping only the textarea lets the
   field keep growing underneath it — measured at 330x640, that left "Your
   Project Is About" floating 140px below the box it labels. Capping the
   field keeps the two locked together, and the textarea simply fills it. */
.dvl-contact__fields .dvl-contact__field:last-child {
  flex: 1 1 auto;
  min-height: 56px;
  max-height: clamp(88px, 16vh, 176px);
}
.dvl-contact__fields .dvl-contact__field:last-child textarea {
  height: 100%;
  max-height: none;
  min-height: 0;
}

/* ==========================================================================
   HEADLINE — "Get In T[tile]uch"
   ========================================================================== */
.dvl-contact__head {
  /* RIGHT-ALIGNED TO THE GRID LINE, not centred. `stretch` first, or a flex
     item shrinks to its text and text-align has nothing to act on. */
  align-self: stretch;
  text-align: right;
  /* THE PAINT BLEED - why the "h" was being cut off.
     This headline is painted with `background-clip: text`, and that fill
     only exists INSIDE the element's box. At -10% tracking the last glyph's
     advance is shortened by 0.1em but its drawing is not, so the right stem
     of the "h" overhangs the box and the part outside gets no gradient: on
     the client's screen the stem came out ~20% thinner, with a hard
     un-antialiased edge exactly on the box line.

     The fix widens the PAINTED area without moving a single glyph: padding
     on the right, and the same amount taken back off the right margin, so
     the content edge - and with it the text and the grid alignment - stays
     exactly where it was. Only the box grows, into space that was margin.

     (An earlier note here claimed no correction was needed. It measured
     Range rects, which are ADVANCE boxes and shrink with the tracking; the
     ink does not. Judge ink by pixels, never by advance.) */
  --dvl-head-bleed: 0.12em;
  margin: 0 calc(var(--dvl-right-inset) - var(--dvl-contact-pad) - var(--dvl-head-bleed))
          clamp(8px, min(3.5vh, 2.4vw), 46px) 0;
  padding-right: var(--dvl-head-bleed);

  font-family: var(--dvl-contact-font-display);
  /* One clamp drives the type AND the prism: dvl-contact.js sizes the tile
     off the slot's measured width, so there is no second breakpoint table
     here to fall out of sync with. */
  /* FIGMA: Inter Regular 400 / 240px / line-height 112% / tracking -10%,
     on a 1920 frame — so 240/1920 = 12.5vw, handing over to the 240px cap
     exactly at 1920. The height term is the short-viewport governor; 12.5vw
     alone is what let a 1740x640 window ask for a headline it had no room
     for. */
  /* CAP 200px, not Figma's 240 — the client's deliberate call (2 Oct 2026),
     first made by hand on the server and then brought back here so an upload
     cannot undo it. With the 12.5vw term it hands over at 1600px wide. */
  font-size: clamp(38px, min(12.5vw, 26vh), 200px);
  font-weight: 400;
  line-height: 1.12;
  letter-spacing: -0.1em;

  /* THE SITE'S INTER IS A VARIABLE FONT WITH AN opsz AXIS (14-32).
     With optical sizing left on, any large heading silently switches to the
     Display cut, whose sidebearings are less than half the Text cut's —
     while Figma renders the Text cut. The two disagree by enough that at
     240px/-10% the glyphs collide. Pinning opsz to 14 is what makes the
     browser agree with the comp. Applies to every large Inter heading on
     this site, not only here. */
  font-optical-sizing: none;
  font-variation-settings: "opsz" 14;
  /* The headline must stay on ONE line: the tile sits inside the word, and a
     wrap would drop the "o" onto a line of its own. The clamp above is sized
     so this never actually clips. */
  white-space: nowrap;
  /* No text-align here: it is set with the grid alignment above. A second
     declaration later in the same rule wins by source order, which is how a
     leftover `center` quietly beat the `right` and left the headline 167px
     short of the grid line. */

  /* THE GRADIENT. `color` first as the fallback: any engine that cannot do
     background-clip:text ignores the three lines under it and renders solid
     ink, rather than the transparent fill that would make the headline
     disappear entirely. */
  color: var(--dvl-contact-ink);
  background-image: linear-gradient(104deg,
                    var(--dvl-contact-ink-fade, #b7b1a6) 0%,
                    var(--dvl-contact-ink) 62%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* THE SLOT. An empty inline-block that reserves the "o" and hosts the
   canvas. Sized in em, so it tracks the fluid font size exactly, and it is
   the POSITIONING CONTEXT for everything inside it — which is what lets the
   canvas be placed in percentages rather than in JavaScript. */
.dvl-contact__o {
  position: relative;
  display: inline-block;
  width: 0.74em;
  height: 0.72em;
  vertical-align: baseline;
  /* A hairline of breathing room so the glass never touches the T or the u.
     Negative margins would be the wrong tool — the prism is sized off this
     box, so shrinking it would shrink the prism with it. */
  margin: 0 0.02em;
  /* The gradient the headline paints on itself is clipped to the TEXT, and
     this box has none — left alone it would inherit the clip and contribute
     nothing. Resetting it here keeps the halo below visible. */
  -webkit-text-fill-color: initial;
}

/* THE HALO. The tile's warm light on the page, in CSS rather than in the
   scene: a glow drawn inside the canvas would be cut off at the canvas edge
   and read as a soft square. This one is unclipped, costs no GPU work, and
   sits BEHIND the canvas (z-index 1 against the canvas's 2). */
.dvl-contact__o::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 1;
  width: 260%;
  height: 260%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(closest-side,
              var(--dvl-contact-halo, rgba(243, 167, 141, 0.42)) 0%,
              rgba(243, 167, 141, 0.16) 46%,
              rgba(243, 167, 141, 0) 72%);
  opacity: 0;
  transition: opacity 0.45s ease;
  pointer-events: none;
}
.dvl-contact--live .dvl-contact__o::before { opacity: 1; }

/* WEBGL FAILED (no context, blocked .glb, ancient browser). Put a real "o"
   back rather than leaving "Get In T uch" with a hole in it, which reads as
   a typo rather than as a missing asset. dvl-contact.js sets this class. */
.dvl-contact--fallback .dvl-contact__o {
  width: auto;
  height: auto;
  margin: 0;
}
.dvl-contact--fallback .dvl-contact__o::before {
  /* Back to being a letter: the halo's box, radius and glow all go, or the
     "o" arrives wearing a peach disc. */
  content: "o";
  position: static;
  width: auto;
  height: auto;
  transform: none;
  border-radius: 0;
  background: none;
  opacity: 1;
}

/* ==========================================================================
   FORM
   --------------------------------------------------------------------------
   Sized and placed to the reference: a column from just right of centre out
   to the right margin, its heading sitting directly above the first field.
   ========================================================================== */
.dvl-contact__form {
  position: relative;
  box-sizing: border-box;
  /* 799px on the 1920 frame = 41.6vw; the cap hands over at 1920. */
  width: min(800px, 41.6vw);
  /* The same grid line as the headline, so the form's right edge and the
     "h" of Touch stay flush however either is retuned. */
  margin: 0 calc(var(--dvl-right-inset) - var(--dvl-contact-pad)) 0 auto;
  align-self: stretch;
  max-width: 100%;
}

.dvl-contact__lead {
  margin: 0 0 clamp(10px, 1.8vh, 20px);
  font-family: var(--dvl-contact-font-mono);
  /* FIGMA: IBM Plex Mono Regular 400 / 36px / line-height auto / -6%, on the
     1920 frame (36/1920 = 1.875vw). */
  font-size: clamp(13px, min(1.875vw, 4vh), 36px);
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: -0.06em;
  color: var(--dvl-contact-ink);
}

.dvl-contact__fields {
  display: flex;
  flex-direction: column;
  gap: var(--dvl-contact-gap);
}

/* A field is a label + control sharing one box. The label is NOT a
   placeholder attribute: a placeholder disappears the moment anyone types,
   taking the only description of the field with it, and it is invisible to
   some screen readers. This one is a real <label> that stays put, with the
   control sitting on top of it — so the field keeps its name while it is
   being filled in. */
.dvl-contact__field {
  position: relative;
  display: block;
}

.dvl-contact__label {
  position: absolute;
  left: clamp(12px, 1.1vw, 20px);
  bottom: clamp(10px, 1.1vh, 16px);
  z-index: 1;
  pointer-events: none;     /* clicks fall through to the control */
  font-family: var(--dvl-contact-font-mono);
  font-size: clamp(11px, min(0.9375vw, 2.2vh), 18px);
  letter-spacing: -0.06em;
  color: var(--dvl-contact-ink-soft);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: opacity 0.18s ease, transform 0.18s ease;
}

/* The label fades as soon as the control has content or focus. :placeholder-shown
   is what makes "has content" work without a line of JavaScript — the control
   carries a single-space placeholder purely so this selector has something to
   test. */
.dvl-contact__field :is(input, textarea):focus ~ .dvl-contact__label,
.dvl-contact__field :is(input, textarea):not(:placeholder-shown) ~ .dvl-contact__label {
  opacity: 0;
  transform: translateY(4px);
}

.dvl-contact__field input,
.dvl-contact__field textarea {
  box-sizing: border-box;
  display: block;
  width: 100%;
  padding: clamp(10px, 1.1vh, 16px) clamp(12px, 1.1vw, 20px);
  border: 0;
  border-radius: var(--dvl-contact-radius);

  /* THE FEATHERED EDGE.
     A flat tone plus a wide, soft halo of the SAME tone. The halo is what
     makes the perimeter bleed into the page instead of ending on a line —
     there is no border and no stroke anywhere on these, by design. A
     gradient fill was the previous attempt and could not do it: a gradient
     stops at the box, so the edge stays hard however soft the ramp is.
     Blur 25 / spread 8 straight from the spec. */
  background: var(--dvl-contact-field);
  box-shadow: 0 0 25px 8px var(--dvl-contact-field-glow);

  font-family: var(--dvl-contact-font-mono);
  /* FIGMA: IBM Plex Mono Regular 400 / 18px / -6% (18/1920 = 0.9375vw). */
  font-size: clamp(11px, min(0.9375vw, 2.2vh), 18px);
  letter-spacing: -0.06em;
  line-height: 1.5;
  color: var(--dvl-contact-ink);
  outline: 0;
  appearance: none;
  transition: box-shadow 0.2s ease, background 0.2s ease;
}

.dvl-contact__field input {
  height: clamp(44px, 5.6vh, 62px);
}

.dvl-contact__field textarea {
  /* No fixed height: the flex rules above size the FIELD, and this fills it.
     The cap lives on the field — see the note there. */
  min-height: 0;
  padding-bottom: clamp(30px, 3.4vh, 44px);  /* room for the label below */
  resize: none;                              /* the page cannot scroll */
  /* The box is sized by the layout, not by `rows`, so when it is shorter
     than four rows the browser offers a scrollbar for an EMPTY field. Hidden
     until there is something to scroll to. */
  overflow-y: auto;
  scrollbar-width: thin;
}
/* The message label sits at the BOTTOM of its box in the reference, under the
   typing area rather than above it — which is why the textarea reserves the
   padding above and the shared .dvl-contact__label rule anchors to `bottom`. */

/* Focus deepens the halo rather than drawing a ring: a ring would be the
   hard edge the whole treatment avoids. The inset line is kept faint and
   comes second so it reads as a lit interior, not a border. */
.dvl-contact__field :is(input, textarea):focus {
  box-shadow: 0 0 30px 10px var(--dvl-contact-field-glow),
              inset 0 0 0 1px rgba(58, 48, 30, 0.14);
}

.dvl-contact__field :is(input, textarea)::placeholder {
  color: transparent;   /* the real label above is the visible one */
}

/* ---- send ---------------------------------------------------------------- */
.dvl-contact__send {
  box-sizing: border-box;
  display: block;
  width: 100%;
  height: clamp(44px, 5.6vh, 62px);
  margin-top: var(--dvl-contact-gap);
  border: 0;
  border-radius: var(--dvl-contact-radius);
  /* Left-weighted, so the button reads as lit from the same side as the glass
     tile above it. */
  background: linear-gradient(95deg,
              var(--dvl-contact-accent) 0%,
              #f8cdbb 46%,
              #f2f0ee 100%);

  /* CRISP, DELIBERATELY. No halo here: the button is the one element on the
     page that has to read as a hard target you can hit. It is the contrast
     with the feathered fields above that makes it look pressable, so do not
     "make it consistent" by adding the glow. */
  box-shadow: none;

  font-family: var(--dvl-contact-font-mono);
  font-size: clamp(11px, min(0.9375vw, 2.2vh), 18px);
  letter-spacing: -0.02em;
  color: var(--dvl-contact-ink);
  cursor: pointer;
  transition: filter 0.2s ease, transform 0.2s ease;
}
.dvl-contact__send:hover { filter: brightness(1.04) saturate(1.06); }
.dvl-contact__send:active { transform: translateY(1px); }
.dvl-contact__send:focus-visible {
  outline: 2px solid var(--dvl-contact-ink);
  outline-offset: 2px;
}
.dvl-contact__send:disabled,
.dvl-contact__send.is-loading {
  opacity: 0.65;
  cursor: not-allowed;
  filter: grayscale(0.2);
}

/* Anti-Spam Honeypot container */
.dvl-contact__hp {
  display: none !important;
  position: absolute !important;
  left: -9999px !important;
  opacity: 0 !important;
  pointer-events: none !important;
}

/* Status Alert Message */
.dvl-contact__status {
  display: none;
  margin-top: clamp(8px, 1.4vh, 14px);
  padding: 10px 14px;
  border-radius: var(--dvl-contact-radius, 3px);
  font-family: var(--dvl-contact-font-mono);
  font-size: clamp(10px, 0.85vw, 13px);
  line-height: 1.4;
  text-align: center;
  letter-spacing: -0.02em;
  transition: all 0.25s ease;
}
.dvl-contact__status.is-success {
  display: block;
  background: rgba(46, 125, 50, 0.08);
  color: #276d2a;
  border: 1px solid rgba(46, 125, 50, 0.25);
}
.dvl-contact__status.is-error {
  display: block;
  background: rgba(211, 47, 47, 0.08);
  color: #c62828;
  border: 1px solid rgba(211, 47, 47, 0.25);
}

/* ==========================================================================
   THE SHARED FOOTER WINS
   --------------------------------------------------------------------------
   dvl-contact.js sets .dvl-contact--has-footer when a Theme Builder footer
   is on the page. When it is, this section's own base row stands down and
   the site's footer does that job — same icons, same address, same layout as
   every other page, which is the whole point. The row below is the fallback
   for a page with no Theme Builder footer assigned, and nothing else.

   The column also stops reserving the row's height, because the footer is
   real chrome now and the section has already given back its height.
   ========================================================================== */
.dvl-contact--has-footer .dvl-contact__base { display: none; }

.dvl-contact--has-footer .dvl-contact__inner {
  padding-bottom: clamp(12px, 3vh, 44px);
}

/* ==========================================================================
   BASE ROW — socials left, address right
   Pinned to the bottom of the section rather than placed in the flow: the
   page is exactly one viewport tall and the row belongs on the bottom margin
   whatever the form above it does.
   ========================================================================== */
.dvl-contact__base {
  position: absolute;
  z-index: 1;
  left: var(--dvl-contact-pad);
  right: var(--dvl-contact-pad);
  bottom: var(--dvl-base-bottom);
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Matches --dvl-base-row, which the column above reserves for it. Change
     one and change the other, or the safe area stops being safe. */
  min-height: var(--dvl-base-row);
  gap: 16px;
}

.dvl-contact__social {
  display: flex;
  align-items: center;
  gap: clamp(14px, 1.9vw, 30px);
}

.dvl-contact__social a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 44px is the minimum comfortable touch target; the icon inside is smaller.
     Negative margins keep the visual rhythm of the reference while the
     clickable box stays honest. */
  width: 44px;
  height: 44px;
  margin: -10px;
  color: var(--dvl-contact-ink);
  text-decoration: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.dvl-contact__social a:hover { opacity: 0.6; transform: translateY(-1px); }
.dvl-contact__social svg {
  width: clamp(18px, 1.35vw, 24px);
  height: auto;
  fill: currentColor;
}

.dvl-contact__mail {
  font-family: var(--dvl-contact-font-mono);
  font-size: clamp(13px, 1.05vw, 19px);
  letter-spacing: 0.01em;
  color: var(--dvl-contact-ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  transition: opacity 0.2s ease;
}
.dvl-contact__mail:hover { opacity: 0.6; }

/* ==========================================================================
   ELEMENTOR FORM WIDGET
   --------------------------------------------------------------------------
   If the form is built with Elementor's Form widget instead of the markup
   above, its fields get the same treatment. Kept to one short block and
   scoped inside #dvl-contact, so it cannot reach a form anywhere else.
   ========================================================================== */
#dvl-contact .elementor-field-group { margin-bottom: var(--dvl-contact-gap); }
#dvl-contact .elementor-field-textual {
  padding: clamp(10px, 1.1vh, 16px) clamp(12px, 1.1vw, 20px);
  border: 0;
  border-radius: var(--dvl-contact-radius);
  background: linear-gradient(180deg,
              var(--dvl-contact-field-edge) 0%,
              var(--dvl-contact-field) 55%,
              var(--dvl-contact-field-edge) 100%);
  font-family: var(--dvl-contact-font-mono);
  color: var(--dvl-contact-ink);
}
#dvl-contact .elementor-button[type="submit"] {
  border: 0;
  border-radius: var(--dvl-contact-radius);
  background: linear-gradient(95deg,
              var(--dvl-contact-accent) 0%, #f8cdbb 46%, #f2f0ee 100%);
  font-family: var(--dvl-contact-font-mono);
  color: var(--dvl-contact-ink);
}

/* ==========================================================================
   TABLET — Elementor's own breakpoint (<= 1024)
   ========================================================================== */
@media (max-width: 1024px) {
  /* Narrower screens cannot afford the full 19.5vw right inset — the form
     would be squeezed to a column of broken labels — so the inset shrinks
     first and the form keeps its width.

     THROUGH THE VARIABLE, NEVER BY OVERRIDING THE MARGIN. The headline and
     the form share one grid line by both hanging off --dvl-right-inset; a
     margin-right set here moved the form alone and pulled the two apart by
     75px at 1024, which is exactly the misalignment this block is supposed
     to avoid. */
  #dvl-contact { --dvl-right-inset: clamp(var(--dvl-contact-pad), 12vw, 160px); }
  .dvl-contact__form { width: min(760px, 62vw); }
  /* Tablet keeps the desktop tokens' shape and only relaxes the caps, so
     there is no third type scale to keep in step with the comp. */
  .dvl-contact__lead { font-size: clamp(13px, min(2.4vw, 4vh), 26px); }
  .dvl-contact__label,
  .dvl-contact__field input,
  .dvl-contact__field textarea,
  .dvl-contact__send { font-size: clamp(11px, min(1.5vw, 2.2vh), 16px); }
}

/* Tablet portrait & desktop: vertically center the headline + form
   so distance to header and distance to footer are completely balanced. */
@media (min-width: 768px) and (min-height: 600px) {
  .dvl-contact__inner,
  .dvl-contact--has-footer .dvl-contact__inner {
    justify-content: center !important;
    padding-top: var(--dvl-header-clear, 0px) !important;
    padding-bottom: var(--dvl-footer-clear, 0px) !important;
  }
}

/* ==========================================================================
   MOBILE — Elementor's own breakpoint (<= 767)
   --------------------------------------------------------------------------
   The page still does not scroll, so the layout has to FIT rather than
   stack-and-hope: the headline drops to two thirds of its desktop ratio, the
   form centres under it, and the message box gives up most of its height.
   ========================================================================== */
@media (max-width: 767px) {
  #dvl-contact { --dvl-contact-gap: 6px; }

  /* TOP-ALIGNED, and tight to the header.

     This was centred, which was the wrong fix for the right problem: with a
     shrink-only form the column did not fill the screen, so centring split
     the slack between top and bottom and pushed the headline a long way down
     under the header — measured at 330x640, about 95px of dead space before
     the type started. The form now grows into that slack instead (see HOW
     THE COLUMN ABSORBS A SHORT VIEWPORT), so the space goes to the message
     box where it is useful, and the headline sits where it belongs. */
  #dvl-contact {
    /* A phone's header bar is shorter than the desktop one. */
    --dvl-header-clear: 58px;
    --dvl-head-top: clamp(var(--dvl-header-clear), 7.5vh, 76px);
    /* Two rows of tiny type, stacked — see the base row rule below. */
    --dvl-base-row: 76px;
  }

  /* FIGMA, phone frame (390): Inter LIGHT 300 / 48px / line-height 120% /
     tracking -2%. A different weight and a much smaller negative tracking
     than the desktop cut — at 48px the -10% desktop tracking would close the
     counters up. 48/390 = 12.3vw.

     CENTRED here, not right-aligned: the desktop grid line exists to hang
     the headline and the form off one vertical, and on a phone the form is
     full-width so there is no second column to align to. */
  .dvl-contact__head {
    align-self: stretch;
    text-align: center;
    /* The same bleed on both sides, so centring is untouched while the
       fill still reaches any ink that overhangs the box. */
    margin-left: calc(-1 * var(--dvl-head-bleed));
    margin-right: calc(-1 * var(--dvl-head-bleed));
    padding-left: var(--dvl-head-bleed);
    padding-right: var(--dvl-head-bleed);

    margin-bottom: clamp(10px, 2.4vh, 22px);
    font-size: clamp(30px, min(12.3vw, 13vh), 48px);
    font-weight: 300;
    line-height: 1.2;
    letter-spacing: -0.02em;
  }

  /* FIGMA phone: IBM Plex Mono 400 / 14px / auto / -4% (14/390 = 3.6vw). */
  .dvl-contact__lead {
    font-size: clamp(11px, 3.6vw, 16px);
    letter-spacing: -0.04em;
  }

  /* FIGMA phone: placeholders IBM Plex Mono 400 / 14px / auto / -6%. */
  .dvl-contact__label,
  .dvl-contact__field input,
  .dvl-contact__field textarea,
  .dvl-contact__send {
    font-size: clamp(11px, 3.6vw, 16px);
    letter-spacing: -0.06em;
  }

  .dvl-contact__form {
    width: 100%;
    margin: 0;
  }

  /* 48px is the minimum comfortable touch target, so the phone layout
     spends its slack on taller fields rather than on white space. */
  .dvl-contact__field input { height: clamp(44px, 6.6vh, 54px); }
  /* A phone has height to spare once the column is top-packed, and the
     message box is the right place to spend it. */
  .dvl-contact__fields .dvl-contact__field:last-child {
    max-height: clamp(96px, 26vh, 240px);
  }
  .dvl-contact__field textarea { padding-bottom: 30px; }
  .dvl-contact__send { height: clamp(44px, 6.6vh, 54px); }

  /* The base row stacks: two lines of tiny type side by side at 375px is
     where the reference's layout stops working. */
  .dvl-contact__base {
    flex-direction: column;
    gap: 10px;
    bottom: clamp(14px, 2.6vh, 22px);
  }
}

/* ==========================================================================
   SHORT VIEWPORTS — the ladder
   --------------------------------------------------------------------------
   The min() terms above already shrink the headline on a short screen, and
   the flex rules already shrink the message box. These two steps take the
   FIXED costs down as well — the space under the header, the gaps, and the
   field heights — because below about 800px tall those are what is left
   over-spending the budget.

   Height-only queries, so they apply to a landscape phone and to a desktop
   window dragged short alike. They deliberately do not mention width: the
   bug being fixed is a wide window that is short.
   ========================================================================== */
@media (max-height: 800px) {
  #dvl-contact {
    --dvl-head-top: clamp(var(--dvl-header-clear), 15vh, 150px);
    --dvl-base-clear: clamp(8px, 1.6vh, 16px);
  }
  .dvl-contact__head {
    font-size: clamp(36px, min(8.6vw, 18vh), 150px);
    margin-bottom: clamp(10px, 3.4vh, 40px);
  }
  .dvl-contact__lead { margin-bottom: clamp(8px, 1.4vh, 14px); }
  .dvl-contact__field input,
  .dvl-contact__send { height: clamp(38px, 6vh, 52px); }
}

@media (max-height: 650px) {
  #dvl-contact {
    --dvl-head-top: clamp(var(--dvl-header-clear), 10vh, 96px);
    --dvl-contact-gap: 6px;
  }
  .dvl-contact__head {
    font-size: clamp(32px, min(7.6vw, 16vh), 118px);
    margin-bottom: clamp(8px, 2.2vh, 22px);
  }
  .dvl-contact__lead {
    font-size: clamp(12px, min(1.4vw, 3.4vh), 18px);
    margin-bottom: clamp(6px, 1.2vh, 12px);
  }
  .dvl-contact__field input,
  .dvl-contact__send { height: clamp(34px, 5.6vh, 44px); }
  .dvl-contact__field textarea { padding-bottom: 26px; }
  .dvl-contact__label { font-size: clamp(11px, min(0.9vw, 2.4vh), 14px); }
}

/* ==========================================================================
   MOBILE LANDSCAPE (viewport height <= 560px and landscape orientation)
   --------------------------------------------------------------------------
   In mobile landscape, the screen height is too short for a static 100vh page.
   Unlocks scroll on html/body and #dvl-contact so the full form, inputs, and
   submit button are completely reachable by scrolling and never cropped.
   ========================================================================== */
@media (max-height: 560px) and (orientation: landscape), (max-height: 480px) {
  html.dvl-contact-lock,
  body.dvl-contact-lock {
    height: auto !important;
    min-height: 100% !important;
    overflow-y: auto !important;
    overflow-x: hidden !important;
    overscroll-behavior: auto !important;
    -webkit-overflow-scrolling: touch !important;
  }

  #dvl-contact {
    height: auto !important;
    min-height: 100vh !important;
    min-height: 100svh !important;
    overflow: visible !important;
    padding-bottom: 30px !important;
  }

  .dvl-contact__inner,
  .dvl-contact--has-footer .dvl-contact__inner {
    height: auto !important;
    min-height: auto !important;
    overflow: visible !important;
    padding-top: max(20px, env(safe-area-inset-top)) !important;
    padding-bottom: 30px !important;
    justify-content: flex-start !important;
  }

  .dvl-contact__base {
    position: relative !important;
    left: auto !important;
    right: auto !important;
    bottom: auto !important;
    margin-top: 28px !important;
    margin-bottom: 16px !important;
    width: 100% !important;
  }

  .dvl-contact__head {
    font-size: clamp(28px, 6.5vh, 40px) !important;
    margin-bottom: 10px !important;
    text-align: center !important;
  }

  .dvl-contact__lead {
    font-size: clamp(12px, 3.4vh, 15px) !important;
    margin-bottom: 10px !important;
    text-align: center !important;
  }

  .dvl-contact__form {
    width: min(600px, 92vw) !important;
    margin: 0 auto !important;
  }

  .dvl-contact__field input,
  .dvl-contact__send {
    height: 44px !important;
  }

  .dvl-contact__field textarea {
    min-height: 72px !important;
    height: 80px !important;
    padding-bottom: 24px !important;
  }
}

/* ==========================================================================
   REDUCED MOTION
   The tile keeps a much-reduced drift (handled in dvl-contact.js — a prism
   frozen dead still reads as a flat image, which is worse than a slow one).
   Here it is only the DOM transitions that go.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .dvl-contact__label,
  .dvl-contact__send,
  .dvl-contact__social a,
  .dvl-contact__mail,
  .dvl-contact__field :is(input, textarea) {
    transition: none;
  }
}
