/* =========================================================================
   Global site styles for the Joe Shew site.

   This file is enqueued on the front end. Put global CSS here — typography,
   buttons, header/footer, Elementor layout support, responsive rules — and
   keep style.css to the theme header only.

   Shared visual treatments (brand colour fills, gradient borders, badges)
   belong here as reusable utility classes so widget stylesheets can point at
   them instead of re-declaring the same literals. See CLAUDE.md.
   ========================================================================= */

/* =========================================================================
   Brand tokens — the Joeshew.com styles from the Figma design system.

   Defined once here and consumed by the js-core widgets as
   var(--js-color-*, <figma fallback>), so a colour change lands in one place.
   Add new brand values here rather than inlining them in a widget stylesheet.
   ========================================================================= */
:root {
  --js-color-primary: #111827;
  --js-color-text: #475569;
  --js-color-white: #ffffff;
  --js-color-border: #b0bed2;
  --js-color-highlight: #b28b2c;
  --js-color-light-bg: #edeff4;

  /* Hover fills for the CTA button: the dark button lightens, the white one
     darkens. Kept as their own tokens rather than folded into the two above —
     white-hover is a near neighbour of light-bg (#eef2f7 vs #edeff4) but not
     the same value, so collapsing them would shift the button. */
  --js-color-primary-hover: #1f2b40;
  --js-color-white-hover: #eef2f7;
}

/* -------------------------------------------------------------------------
   Desktop page gutter.

   The kit gives a top-level container 32px of side padding at tablet, 16 at
   mobile, and nothing at all on desktop — desktop instead relies on the 1200px
   content width being narrower than the screen, which stops being true the
   moment the screen is narrower than 1200. Between 1025, where the tablet
   padding stops, and 1264, where centring a 1200px box first leaves 32px of
   its own, every section runs flush to both edges: headings against the glass,
   the last nav link clipped by it, the enquiry photograph cut off.

   The gutter goes on the content box rather than back on the container as
   padding, and that is the point: --content-width caps .e-con-inner only,
   while side padding sits on .e-con itself and would pull every full-bleed
   background in with it. min() keeps the 1200 wherever it fits, so nothing
   moves at 1264 and above, and the handover from the tablet padding at 1024 is
   seamless — 32px either side of it.

   e-parent, not every container: a nested container carries --content-width
   too, and clamping those as well would inset each child a second time inside
   a parent that is already inside the gutter.

   This is kit data really — Site Settings > Layout, the same three fields the
   32 and the 16 come from — and it belongs there. It is here because that is
   what this repo can deploy. A container with side padding of its own (one
   section carries 120) gets that padding plus the 32 below 1264; it has no
   edge to run off in the first place, so the cost is 32px of width on one
   section at widths the design does not draw. */
@media (min-width: 1025px) {
  .e-con.e-parent {
    --content-width: min(100% - 64px, var(--container-max-width, 1200px));
  }
}

/* -------------------------------------------------------------------------
   Photo plate — the treatment a hero photo gets when copy rides over it.

   Below desktop the story section (21381:21440) and the click testimonial
   (22460:23047) both stack the same way: a photo, a vignette over it, and then
   white — transparent across the face and fully opaque by the photo's bottom
   edge — so the block underneath can overlap that edge by 80px and still read
   as though it were sitting on the page.

   Tokens rather than literals because two places draw them, and the fade is
   what makes the overlap legible: change one and the other must follow.
   ------------------------------------------------------------------------- */
:root {
  /* How far the copy rides up over the photo. */
  --js-photo-overlap: 80px;

  /* The vignette: a soft ellipse over the middle, plus a fall to near-black at
     the foot of the frame. Half strength, as the design layer is. */
  --js-photo-scrim:
    radial-gradient(
      204.74px 179.07px at 50% 40.31%,
      rgba(0, 16, 38, 0) 0%,
      rgba(0, 16, 38, 0.28) 100%
    ),
    linear-gradient(
      180deg,
      rgba(0, 16, 38, 0) 53.29%,
      rgba(0, 11, 26, 1) 102.41%
    );
  --js-photo-scrim-opacity: 0.5;

  /* How the photo ends. The design draws this as white painted over the photo,
     which only works where the page behind it is white — over the story
     section's grey it left a white block with a visible edge. So it is a mask
     on the photo instead: the photo itself fades out and whatever is behind it
     comes through, white or grey or anything else.

     The curve is the design's own (Rectangle 23), read straight off it and
     inverted: transparent until 22.83%, three quarters gone by 73.52%, and
     nothing left at the bottom edge. That last stop is the point — the copy
     overlaps the bottom 80px, which is what the heading occupies, so the photo
     stays visible right through the heading and is gone directly under it.
     Ending the fade higher clears the text with room to spare but cuts the
     photograph off in mid-air. */
  --js-photo-fade-start: 22.83%;
  --js-photo-fade-mid: 73.52%;
  --js-photo-fade-mid-alpha: 0.25;

  --js-photo-fade: linear-gradient(
    180deg,
    #000 var(--js-photo-fade-start),
    rgba(0, 0, 0, var(--js-photo-fade-mid-alpha)) var(--js-photo-fade-mid),
    transparent 100%
  );
}

/* -------------------------------------------------------------------------
   Type scale — the Figma text styles, read from the file's own variables
   (Text/Display Lg, Text/Display Md, Text/H1, Text/Body *). Everything is
   Inter, and every step is a size/line-height pair rather than a size and a
   ratio, because that is how the design defines them.

   Widgets consume these as var(--js-font-*, <fallback>). Do not invent sizes
   between the steps: if a design needs one, it belongs here first.
   ------------------------------------------------------------------------- */
:root {
  --js-font-family: "Inter", sans-serif;

  /* Display Lg — 56/64, 600 */
  --js-font-display-lg-size: 56px;
  --js-font-display-lg-line: 64px;

  /* Display Md — 48/56, 600, letter-spacing -0.5 */
  --js-font-display-md-size: 48px;
  --js-font-display-md-line: 56px;

  /* H1 — 36/48, 600 */
  --js-font-h1-size: 36px;
  --js-font-h1-line: 48px;

  /* Body Lg — 18/28, 400 */
  --js-font-body-lg-size: 18px;
  --js-font-body-lg-line: 28px;

  /* Body Md — 16/24, 400 */
  --js-font-body-md-size: 16px;
  --js-font-body-md-line: 24px;

  /* Body Sm — 14/20, 400 or 600 */
  --js-font-body-sm-size: 14px;
  --js-font-body-sm-line: 20px;

  --js-font-weight-regular: 400;
  --js-font-weight-semibold: 600;
}

/* -------------------------------------------------------------------------
   Clip the page's horizontal overflow.

   The carousel deliberately lets its faded edge cards run past the container
   toward the screen edges, and js-carousel.css says in as many words that the
   theme is expected to clip them: "the theme clips html/body overflow-x, so
   this can't add a horizontal scrollbar". That rule was never written, so the
   overflow reached the document — 2036px of scroll width against a 375px
   viewport on mobile, and 1917 against 1414 on desktop.

   clip rather than hidden: hidden would make the root a scroll container,
   which breaks position: sticky for everything inside it. Nothing is sticky
   today, but the nav is the obvious candidate and this costs nothing.
   ------------------------------------------------------------------------- */

html {
  overflow-x: hidden; /* fallback for browsers without clip */
  overflow-x: clip;
}

/* -------------------------------------------------------------------------
   Neutralise the parent theme's button chrome.

   Hello Elementor's reset.css gives every <button> a #c36 border and #c36
   text, and fills it #c36 with white text on hover and focus. Nothing in this
   design uses that colour.

   Our widgets already reset the resting state, but they do it on a single
   class (0,1,0) and the theme's button:hover is (0,1,1), so the theme won
   every hover: a pink block behind the testimonial avatars and the nav
   hamburger, and — because the icons inside them are drawn with currentColor
   — white bars and white arrows on top of it.

   The resting state needs undoing too: every widget resets the border but not
   the colour, so a button sat at #c36 and anything inside it drawn from
   currentColor would have inherited that. Each widget sets its own padding and
   background, so zeroing them here costs nothing.
   ------------------------------------------------------------------------- */

button,
[type="button"],
[type="submit"] {
  padding: 0;
  border: 0;
  border-radius: 0;
  background-color: transparent;
  color: inherit;
}

button:hover,
button:focus,
[type="button"]:hover,
[type="button"]:focus,
[type="submit"]:hover,
[type="submit"]:focus {
  background-color: transparent;
  color: inherit;
}

/* -------------------------------------------------------------------------
   Base typography — the scale above, applied.

   The block above only defines the tokens. Elementor's kit sets the family
   and weight but nothing else, so body copy fell through to the browser's
   16px/normal — a step below the design's Body Lg, which is why paragraphs
   wrapped to fewer lines than the Figma frames (the story section's copy came
   out 221px tall against the design's 277px).
   ------------------------------------------------------------------------- */

/* The parent theme's reset leaves body text at #333; the design's is the Text
   token. Widgets that set their own colour are unaffected. */
body {
  color: var(--js-color-text);
}

/* A paragraph's bottom margin is the space to whatever follows it. The last one
   in a block has nothing following, so that margin is only padding the block
   did not ask for — and it fights every gap set on the container. */
p:last-child {
  margin-bottom: 0;
}

/* Body copy: Text Editor is the widget the design's paragraphs live in. */
.elementor-widget-text-editor {
  font-size: var(--js-font-body-lg-size);
  line-height: var(--js-font-body-lg-line);
}

/* Display Md is 48/56 with -0.5 tracking. The kit already sizes h2 to match,
   so the tracking is the only part it cannot express. */
.elementor-widget-heading h2.elementor-heading-title {
  letter-spacing: -0.5px;
}

/* -------------------------------------------------------------------------
   Trimmed text boxes.

   Every text layer in the Figma file carries text-box-trim, so the frames'
   numbers are cap-height boxes rather than line boxes: a two-line 56/64
   heading measures 105 there and 128 here, a 16/24 field label measures 12
   there and 24 here. Read as line boxes, every gap a frame specifies quietly
   gains half a line above and below the block it separates — which is what
   made the enquiry form outgrow the photograph beside it by 130px, and which
   has been loosening every section built off these frames by the same kind of
   margin, just less visibly.

   Trimmed here so the space between blocks is the space the frames draw.
   Longhands alongside the shorthand for older engines; anything supporting
   neither renders as it did before, slightly looser, and nothing breaks —
   which is why this is safe to apply across the site rather than per section.

   Only text that flows in a block. Anything centred inside a box of its own
   height is left out — a button, a nav link, a pill, the timeline's year
   badge — because there the line box is what the centring is measured
   against, and trimming it moves the label off centre for nothing.
   ------------------------------------------------------------------------- */
.elementor-widget-heading .elementor-heading-title,
.elementor-widget-text-editor p,
.js-hero__eyebrow,
.js-hero__heading,
.js-hero__description,
.js-timeline__heading,
.js-timeline__body,
.js-stats__value,
.js-stats__label,
.js-testimonial__quote,
.js-testimonial__name,
.js-testimonial__role,
.js-click-testimonial__quote,
.js-click-testimonial__avatar-name,
.js-carousel__title,
.js-carousel__card-title,
.js-carousel__card-sub,
.js-carousel__name,
.js-carousel__media-caption,
.js-video-cards__title,
.js-logo-row__label,
.js-footer-bottom__disclaimer,
.js-footer-bottom__copyright,
.js-form .elementor-field-label,
.js-form .elementor-field-type-html {
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
  text-box: trim-both cap alphabetic;
}

/* -------------------------------------------------------------------------
   Shared utility classes.
   ------------------------------------------------------------------------- */

/* The photo plate as classes, for the places built in Elementor rather than in
   a widget (the story section's Image widget). Put .js-photo-plate on the
   image and .js-photo-overlap on the block that rides over it.

   The story section's own elements are named alongside those classes rather
   than given their own copies of the rules: the classes cannot be attached to
   an Elementor element from here, only from the builder.

   .js-photo-plate is now attached to the story section's Responsive Image, so
   that one no longer needs an id. It mattered there: the widget's id is
   generated by Elementor and changes whenever the widget is rebuilt, which is
   exactly what broke this binding once already.

   The copy column keeps its id. Elementor 4.2.4 registers no CSS-classes
   control on a container at all — the field is widget-only — so there is no
   class to attach. That is not the problem it would be for a widget:
   b1000002 is one of our own hand-authored ids, not a generated one, so it is
   as stable as a class would be.

   Scoped to tablet and below: only there does the design stack the two and
   overlap them. On desktop the photo sits beside the copy, untouched. */
@media (max-width: 1024px) {
  .js-photo-plate {
    position: relative;
    /* The mask takes the whole plate — image and vignette together — so the
       two fade out as one. It also makes the plate its own layer, which is
       what keeps it under the copy riding over it: the vignette is z-index 1
       and so is that copy, but it comes earlier in the DOM and would lose the
       tie. */
    -webkit-mask-image: var(--js-photo-fade);
    mask-image: var(--js-photo-fade);
    isolation: isolate;
  }

  .js-photo-plate::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    border-radius: 24px;
    pointer-events: none;
    background-image: var(--js-photo-scrim);
    opacity: var(--js-photo-scrim-opacity);
  }

  .js-photo-overlap,
  .elementor-element-b1000002,
  .elementor-element-h0000003 {
    position: relative;
    z-index: 2;
    margin-top: calc(-1 * var(--js-photo-overlap));
  }
}

/* -------------------------------------------------------------------------
   Story + Featured In, tablet and below (21381:21438, 21373:16199).

   Below desktop the section stops being two columns beside each other and
   becomes one: the photo on top, and the heading riding over its bottom edge
   on the white the plate above leaves behind.

   All of this is page data really — the builder can express every line of it —
   and it should move there. It is here because it is what the frames show and
   the section can be made to match now. The one part that genuinely reads as a
   contradiction in the builder is the photo: the Image column is set to hide on
   tablet and mobile, so it is forced back on below. Clearing that flag in
   Elementor is the proper fix and this rule then does nothing.
   ------------------------------------------------------------------------- */
@media (max-width: 1024px) {
  /* The photo column: shown, and first. column-reverse rather than reordering
     the children, because the container has exactly two and the design wants
     them the other way round at every width below desktop.

     Every rule in this block carries .elementor-element as well as the id
     class: Elementor emits its own values at (0,3,0) from the page stylesheet,
     and a plain id selector is (0,2,1) — it loses, silently. */
  body .elementor-element.elementor-element-b1000006 {
    display: flex !important;
    --width: 100%;
    /* The heading rides 140px up rather than 80, so it lands around the middle
       of the photo where the shared curve is barely half done — dark text on a
       dark crop. The fade starts earlier and is nearly out by the time the
       words begin, which leaves the top of the picture intact and the heading
       on something close to background. */
    --js-photo-fade-start: 12%;
    --js-photo-fade-mid: 52%;
    --js-photo-fade-mid-alpha: 0.22;
  }

  body .elementor-element.elementor-element-b1000001 {
    --flex-direction: column-reverse;
    /* Desktop's 52px between the two columns would sit between the photo and
       the copy and eat most of the 80px overlap. */
    --gap: 0px 0px;
    --row-gap: 0px;
    --column-gap: 0px;
  }

  /* 32px between the heading, the copy and the logos — the frames' spacing;
     desktop's is 40. */
  body .elementor-element.elementor-element-b1000002 {
    --gap: 32px 32px;
    --row-gap: 32px;
    --column-gap: 32px;
    /* The heading sits higher over the photo here than the 80px the plate
       assumes: 140 at tablet, 150 on a phone. It still ends inside the photo,
       so the fade — which runs out at the photo's bottom edge — still carries
       it, and there is more picture left under the words. */
    --js-photo-overlap: 140px;
  }

  /* The heading steps down from the desktop 48/56. */
  body .elementor-element.elementor-element-b1000003 .elementor-heading-title {
    font-size: 32px;
    line-height: 40px;
  }

  /* And the copy from Body Lg to Body Md, which is what gives the frames
     their 7 lines at tablet and 13 at mobile. */
  body .elementor-element.elementor-element-b1000004 {
    font-size: var(--js-font-body-md-size);
    line-height: var(--js-font-body-md-line);
  }
}

@media (max-width: 767px) {
  body .elementor-element.elementor-element-b1000002 {
    --js-photo-overlap: 150px;
  }

  body .elementor-element.elementor-element-b1000003 .elementor-heading-title {
    font-size: 28px;
    line-height: 36px;
  }

  /* The heading carries a 320px cap from the builder, inside a 343 column.
     The frame gives it the whole column and wraps it "From Young Investor to /
     Global Crypto Educator" — the cap breaks it somewhere else. */
  body .elementor-element.elementor-element-b1000003 {
    width: 100%;
    max-width: 100%;
    --container-widget-width: 100%;
  }
}

/* -------------------------------------------------------------------------
   Page hero: the photo behind the copy on desktop, above it below.

   The interior-page hero — Figma 21842:4480 (desktop), 21997:17385 (tablet),
   21994:12927 (mobile).

   The class goes on the image widget, not the section. Elementor 4.2.4
   registers no CSS-classes control on a container at all (see the story
   section above), so a section-level class has nowhere to go — and needs
   none: .e-con is already position:relative, which makes the section the
   containing block the photo absolutely positions against. The copy
   container has the same problem and takes the same way out as the story
   section's copy column, by id, on the .js-photo-overlap rule above.

   This is its own utility rather than .js-photo-plate because the two differ
   in one respect: the plate carries the story section's dark vignette, and
   these frames draw no vignette — only the fade. The fade itself is the
   shared --js-photo-fade token, which was read off the same Rectangle 23
   these frames use, so the curve is common and only the vignette is not.
   ------------------------------------------------------------------------- */

/* The hero section runs edge to edge. Elementor drops content_width and width
   from this container whenever the page is saved, and even with e-con-full
   sticking, --width falls back to the content width, so the section sizes
   itself to 1200 and centres — which is what made the photograph stop short of
   the right edge in the editor while the front end looked right.

   Stated here instead, by the same hand-authored id the copy column uses,
   since a container takes no CSS-classes control. The selector carries
   .elementor-element as well as the id for the reason recorded against the
   story section above: Elementor emits its own values at (0,3,0) from the page
   stylesheet and a plainer selector loses to them silently. */
body .elementor-element.elementor-element-h0000001 {
  width: 100%;
  max-width: 100%;
  margin-left: 0;
  margin-right: 0;
}

/* The photograph runs edge to edge but the copy does not: it keeps to the same
   1200 column the rest of the site is set in, so a wide screen does not leave
   the heading stranded against the left gutter with the subject far away.

   The copy's containing block is the section's content box, 240 narrower than
   the section itself, so the offset that puts its left edge where a centred
   1200 column would start is (100% - 1200px) / 2 — which comes out at 0 at
   1440, exactly the 120 inset the frame draws, and grows from there. max()
   holds it at 0 below that rather than pulling the copy off the left edge. */
@media (min-width: 1025px) {
  body .elementor-element.elementor-element-h0000003 {
    margin-left: max(0px, calc((100% - 1200px) / 2));
  }
}

/* Below desktop: a band above the copy that fades out into the page. */
.js-hero-photo {
  -webkit-mask-image: var(--js-photo-fade);
  mask-image: var(--js-photo-fade);
}

@media (min-width: 1025px) {
  /* Desktop: the photo stops being a band and becomes the section's backdrop,
     spanning it edge to edge behind the copy. No fade here — the white comes
     from the scrim below, which runs across rather than down. */
  .js-hero-photo {
    position: absolute;
    inset: 0;
    z-index: 0;
    margin: 0;
    -webkit-mask-image: none;
    mask-image: none;
  }

  /* The <picture> the Responsive Image widget renders is display:block but
     auto-height, so the img's height:100% would have nothing to resolve
     against and the photo would keep its own aspect ratio. */
  .js-hero-photo picture,
  .js-hero-photo .js-responsive-image {
    display: block;
    width: 100%;
    height: 100%;
  }

  /* Two classes, because Elementor's base stylesheet sets
     `.elementor img { height: auto }` at (0,1,1) — a single class loses and
     the photo keeps its own aspect ratio instead of filling the section. */
  .js-hero-photo .js-responsive-image__img,
  .js-hero-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  /* The scrim: white on the left, gone before the subject on the right.

     The frame draws this as two gradients, at -81.86deg and 211.86deg, and
     those angles describe the design only at the frame's own 1440x600. An
     angled gradient is geometry relative to the box it paints: widen the box
     and the same angles swing the wash further across it. Past about 1900 the
     211.86deg one reads as almost vertical and takes the bottom half of the
     photograph with it, which is not a wider version of the design — it is a
     different picture.

     So: the same effect, stated so it does not depend on the aspect ratio.
     The hero's height is fixed at 600, so only the width varies, and a
     horizontal gradient is stable under that. The stops are where the frame's
     white actually falls at 1440 — solid behind the copy, gone before the
     photograph has to carry the subject. */
  .js-hero-photo::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-image:
      /* The wash the frame's second gradient leaves across the foot of the
         picture. Vertical, so it is safe: the hero's height is fixed at 600
         and only its width varies. */
      linear-gradient(
        to top,
        rgba(255, 255, 255, 0.45) 0%,
        rgba(255, 255, 255, 0) 60%
      ),
      /* The main scrim. */
      linear-gradient(
        to right,
        rgb(255, 255, 255) 0%,
        rgb(255, 255, 255) 45%,
        rgba(255, 255, 255, 0) 72%
      );
  }
}

/* -------------------------------------------------------------------------
   Enquiry form section (Figma 23001:11585).

   A photograph on one side and a form on the other. Both halves reuse what is
   already here: the photo carries the same --js-photo-scrim the story section
   does, and the submit button is the Primary Button Dark the CTA widget draws.
   ------------------------------------------------------------------------- */

/* The two halves share the row evenly. Elementor gives a flex child width
   auto, so each sizes to its own content — and the Responsive Image widget is
   width:100%, which made its half claim the whole row and push the form
   underneath it. flex-basis 0 is what makes them halves rather than "whatever
   they happen to contain".

   Desktop only: below the breakpoint the row becomes a column, where equal
   bases would stretch the two to equal heights instead of stacking them. By id
   because a container takes no CSS-classes control, the same way the hero and
   the story section do it. */
@media (min-width: 1025px) {
  body .elementor-element.elementor-element-sp000001 > .e-con-inner > .e-con {
    flex: 1 1 0;
    min-width: 0;
  }

  /* The photograph fills the row where it can, but never crops tighter than
     the frame does.

     Two failures to avoid, and they pull opposite ways. Left to its own
     aspect ratio the photo takes its height from its width, so the two halves
     only agree at 1440 and drift apart below 1200, where the columns narrow
     and the form's height barely moves. Stretched to the form outright, at
     1100 it becomes 524 wide by 899 tall — far taller than the frame's
     574x750 — and object-fit eats the sides.

     So: the frame's ratio as the starting point, capped at the row's height.
     It comes out level wherever the form is the shorter of the two, which is
     every width from 1200 up, and at narrower widths it keeps the frame's
     proportion and centres instead, leaving white above and below rather than
     a crop nobody drew. */
  body .elementor-element.elementor-element-sp000002 > .e-con-inner {
    height: 100%;
    justify-content: center;
  }

  body .elementor-element.elementor-element-sp000002 .js-form-photo {
    aspect-ratio: 574 / 750;
    height: auto;
    max-height: 100%;
  }
}

/* The photo plate. Its own aspect ratio rather than a fixed height, so it
   holds the frame's 574x750 at any column width. This is not .js-photo-plate:
   that one masks the photo away at its foot for copy to ride over, which this
   section does not do — only the vignette is shared. */
.js-form-photo {
  position: relative;
  isolation: isolate;
  aspect-ratio: 574 / 750;
  border-radius: 24px;
  overflow: hidden;
}

/* Below desktop the section stops being two columns and becomes the same
   treatment the hero takes: a 300px band, faded out at its foot with the very
   curve --js-photo-fade was read off, and the copy riding up the 80px
   --js-photo-overlap already holds. Figma 23011:11746 and 23011:11665.

   The frames draw the vignette here too, which is the ::after below — so this
   is .js-photo-plate in everything but name, and stays a class of its own only
   because its desktop half is a backdrop rather than a band. The mask sits on
   the element, so it takes the vignette with it, which is the order the frames
   stack them in. */
@media (max-width: 1024px) {
  /* 300px tall at the tablet frame's own width, and the same crop either side
     of it.

     The photograph is a portrait — 1959x2560, the frame's 574x750 — so a band
     across the column shows whatever slice 300px leaves room for, and that
     slice narrows as the column widens: at 768 the picture scales to 704x920
     and the band keeps the middle 300 of it, which on this photograph is a
     torso with no head on it. Past 768 it only tightens further — by 1000 the
     band is 934 wide and holds a quarter of the picture, which is a face.

     So the 300 is held as a ratio instead of a height. 704x300 is the band the
     tablet frame draws — 768 less the section's 32px gutters — and keeping
     that ratio keeps the slice of the photograph constant: still 300 at 768,
     398 at 1000, 409 at 1024, and the same composition at each. min-height
     puts the floor back for phones, where the column is narrower than the
     ratio wants and the mobile frame's own 300 takes over.

     A width cap does hold the crop still too, and was tried — but the band
     then sits narrower than the form beneath it, and a plate that does not
     line up with the section it belongs to reads as the mistake instead. */
  .js-form-photo {
    aspect-ratio: 704 / 300;
    height: auto;
    min-height: 300px;
    -webkit-mask-image: var(--js-photo-fade);
    mask-image: var(--js-photo-fade);
  }

  /* And the crop is taken from near the top of the picture rather than its
     middle, which is where object-fit starts. 13% of the overhang: far enough
     down to lose the black ceiling above him, high enough that his head clears
     the top edge by about 30px at every width — the ratio above is what makes
     one number do that, since the overhang and his place in it now grow
     together. */
  .js-form-photo .js-responsive-image__img {
    object-position: 50% 13%;
  }

  /* The copy rides over the foot of the photograph. By id: a container takes
     no CSS-classes control, the same as the story section's copy column. */
  body .elementor-element.elementor-element-sp000003 {
    position: relative;
    z-index: 2;
    margin-top: calc(-1 * var(--js-photo-overlap));
  }
}

.js-form-photo .js-responsive-image,
.js-form-photo picture {
  display: block;
  width: 100%;
  height: 100%;
}

/* Two classes: Elementor's `.elementor img { height: auto }` is (0,1,1) and a
   single class ties with it rather than winning. */
.js-form-photo .js-responsive-image__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 0;
}

.js-form-photo::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background-image: var(--js-photo-scrim);
  opacity: var(--js-photo-scrim-opacity);
}

/* -------- The form -------------------------------------------------------

   Elementor Pro's Form widget, dressed to the frame's field style. The widget
   exposes colours but not the border, radius or height, so those come from
   here. Put .js-form on the widget. */

.js-form .elementor-form-fields-wrapper {
  row-gap: 12px;
}

.js-form .elementor-field-group > .elementor-field-label {
  margin-bottom: 12px;
  color: var(--js-color-primary, #111827);
  font-family: "Inter", sans-serif;
  font-size: var(--js-font-body-md-size, 16px);
  font-weight: var(--js-font-weight-semibold, 600);
  line-height: var(--js-font-body-md-line, 24px);
}

.js-form .elementor-field-textual {
  min-height: 55px;
  padding: 0 16px;
  border: 1px solid var(--js-color-border, #b0bed2);
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.05);
  color: var(--js-color-text, #475569);
  font-family: "Inter", sans-serif;
  font-size: var(--js-font-body-md-size, 16px);
  line-height: var(--js-font-body-md-line, 24px);
}

.js-form textarea.elementor-field-textual {
  height: 200px;
  min-height: 200px;
  padding: 16px;
  resize: vertical;
}

.js-form .elementor-field-textual::placeholder {
  color: rgba(71, 85, 105, 0.25);
  opacity: 1;
}

/* The note under the textarea, carried as an HTML field so it sits inside the
   form's own flow where the frame puts it. */
.js-form .elementor-field-type-html {
  color: var(--js-color-text, #475569);
  font-family: "Inter", sans-serif;
  font-size: var(--js-font-body-sm-size, 14px);
  line-height: var(--js-font-body-sm-line, 20px);
}

/* The submit button is Primary Button Dark. It cannot literally reuse .js-cta:
   that class lives in the plugin's js-cta-button.css, which is registered
   against the CTA widget and so is not loaded on a page without one, and
   Elementor's submit button takes no CSS-classes control either. So the look is
   restated from the same tokens — js-cta-button.css remains where the variants
   are defined, and this must follow it if they change. */
.js-form .elementor-field-type-submit .elementor-button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 55px;
  padding: 0 40px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: var(--js-color-primary, #111827);
  color: var(--js-color-white, #ffffff);
  font-family: "Inter", sans-serif;
  font-size: var(--js-font-body-lg-size, 18px);
  font-weight: var(--js-font-weight-semibold, 600);
  line-height: var(--js-font-body-md-line, 24px);
  transition: background-color 0.2s ease;
}

.js-form .elementor-field-type-submit .elementor-button:hover,
.js-form .elementor-field-type-submit .elementor-button:focus-visible {
  background: var(--js-color-primary-hover, #1f2b40);
}

.js-color-highlight,
.js-color-highlight .elementor-heading-title {
  color: var(--js-color-highlight);
}

.js-color-primary,
.js-color-primary .elementor-heading-title {
  color: var(--js-color-primary);
}

.js-bg-primary {
  background-color: var(--js-color-primary);
  color: var(--js-color-white);
}

.js-border {
  border: 1px solid var(--js-color-border);
}
